/// <summary>Releases the emergency brake</summary> internal void UnapplyEmergencyBrake() { if (Handles.EmergencyBrake.Driver) { // sound Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } // apply if (Handles.Brake is AirBrakeHandle) { ApplyAirBrakeHandle(AirBrakeHandleState.Service); } else { ApplyNotch(0, !Handles.SingleHandle, Handles.Brake.MaximumNotch, true); } Handles.EmergencyBrake.Driver = false; // plugin if (Plugin == null) { return; } Plugin.UpdatePower(); Plugin.UpdateBrake(); } }
/// <summary>Triggers the playback of a sound</summary> /// <param name="Direction">The direction of travel- 1 for forwards, and -1 for backwards</param> /// <param name="TriggerType">They type of event which triggered this sound</param> /// <param name="Train">The root train which triggered this sound</param> /// <param name="CarIndex">The car index which triggered this sound</param> internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (SuppressSoundEvents) { return; } if (TriggerType == EventTriggerType.FrontCarFrontAxle | TriggerType == EventTriggerType.OtherCarFrontAxle | TriggerType == EventTriggerType.OtherCarRearAxle | TriggerType == EventTriggerType.RearCarRearAxle) { if (!PlayerTrainOnly | Train == TrainManager.PlayerTrain) { Vector3 p = this.Position; double pitch = 1.0; double gain = 1.0; Sounds.SoundBuffer buffer = this.SoundBuffer; if (buffer != null) { if (this.Dynamic) { double spd = Math.Abs(Train.Specs.CurrentAverageSpeed); pitch = spd / this.Speed; gain = pitch < 0.5 ? 2.0 * pitch : 1.0; if (pitch < 0.2 | gain < 0.2) { buffer = null; } } if (buffer != null) { Sounds.PlaySound(buffer, pitch, gain, p, Train, CarIndex, false); } } this.DontTriggerAnymore = this.Once; } } }
/// <summary>The default constructor</summary> internal Horn() { this.StartSound = null; this.LoopSound = null; this.EndSound = null; this.Loop = false; }
/// <summary>Applies a loco brake notch to this train</summary> /// <param name="NotchValue">The loco brake notch value</param> /// <param name="Relative">Whether this is relative to the current notch</param> internal void ApplyLocoBrakeNotch(int NotchValue, bool Relative) { int b = Relative ? NotchValue + Handles.LocoBrake.Driver : NotchValue; if (b < 0) { b = 0; } else if (b > Handles.LocoBrake.MaximumNotch) { b = Handles.LocoBrake.MaximumNotch; } // brake sound if (b < Handles.LocoBrake.Driver) { // brake release Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.Brake.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } if (b > 0) { // brake release (not min) buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // brake min buffer = Cars[DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if (b > Handles.LocoBrake.Driver) { // brake Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleApply.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } Handles.LocoBrake.Driver = b; Handles.LocoBrake.Actual = b; //TODO: FIXME }
/// <summary>Opens the left-hand or right-hand doors for the specified train</summary> /// <param name="Train">The train</param> /// <param name="Left">Whether to open the left-hand doors</param> /// <param name="Right">Whether to open the right-hand doors</param> internal static void OpenTrainDoors(Train Train, bool Left, bool Right) { bool sl = false, sr = false; for (int i = 0; i < Train.Cars.Length; i++) { if (Left & !Train.Cars[i].Doors[0].AnticipatedOpen) { Train.Cars[i].Doors[0].AnticipatedOpen = true; sl = true; } if (Right & !Train.Cars[i].Doors[1].AnticipatedOpen) { Train.Cars[i].Doors[1].AnticipatedOpen = true; sr = true; } } if (sl) { for (int i = 0; i < Train.Cars.Length; i++) { Sounds.SoundBuffer buffer = Train.Cars[i].Doors[0].OpenSound.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[i].Doors[0].OpenSound.Position; Sounds.PlaySound(buffer, Train.Cars[i].Specs.DoorOpenPitch, 1.0, pos, Train, i, false); } for (int j = 0; j < Train.Cars[i].Doors.Length; j++) { if (Train.Cars[i].Doors[j].Direction == -1) { Train.Cars[i].Doors[j].DoorLockDuration = 0.0; } } } } if (sr) { for (int i = 0; i < Train.Cars.Length; i++) { Sounds.SoundBuffer buffer = Train.Cars[i].Doors[1].OpenSound.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[i].Doors[1].OpenSound.Position; Sounds.PlaySound(buffer, Train.Cars[i].Specs.DoorOpenPitch, 1.0, pos, Train, i, false); } for (int j = 0; j < Train.Cars[i].Doors.Length; j++) { if (Train.Cars[i].Doors[j].Direction == 1) { Train.Cars[i].Doors[j].DoorLockDuration = 0.0; } } } } }
internal Horn(Sounds.SoundBuffer startSound, Sounds.SoundBuffer loopSound, Sounds.SoundBuffer endSound, bool loop) { this.Source = null; this.StartSound = startSound; this.LoopSound = loopSound; this.EndSound = endSound; this.Loop = loop; this.StartEndSounds = false; this.LoopStarted = false; SoundPosition = new Vector3(); }
/// <param name="TrackPositionDelta">The delta position of the sound within a track block.</param> /// <param name="SoundBuffer">The sound buffer to play. /// HACK: Set to a null reference to indicate the train point sound.</param> /// <param name="PlayerTrainOnly">Defines whether this sound is played for the player's train only, or for player and AI trains</param> /// <param name="Once">Defines whether this sound repeats looped, or plays once</param> /// <param name="Dynamic">Whether this sound is dynamic (Attached to a train)</param> /// <param name="Position">The position of the sound relative to it's track location</param> /// <param name="Speed">The speed in km/h at which this sound is played at it's original pitch (Set to zero to play at original pitch at all times)</param> internal SoundEvent(double TrackPositionDelta, Sounds.SoundBuffer SoundBuffer, bool PlayerTrainOnly, bool Once, bool Dynamic, Vector3 Position, double Speed) { this.TrackPositionDelta = TrackPositionDelta; this.DontTriggerAnymore = false; this.SoundBuffer = SoundBuffer; this.PlayerTrainOnly = PlayerTrainOnly; this.Once = Once; this.Dynamic = Dynamic; this.Position = Position; this.Speed = Speed; }
/// <summary>Attempts to load a sound file into a car-sound</summary> /// <param name="FileName">The sound to load</param> /// <param name="Position">The position that the sound is emitted from within the car</param> /// <param name="Radius">The sound radius</param> /// <returns>The new car sound, or an empty car sound if load fails</returns> internal CarSound(string FileName, Vector3 Position, double Radius) { this = TrainManager.CarSound.Empty; this.Position = Position; this.Source = null; if (FileName != null) { if (System.IO.File.Exists(FileName)) { this.Buffer = Sounds.RegisterBuffer(FileName, Radius); } } }
/// <summary>Applies a reverser notch</summary> /// <param name="Value">The notch to apply</param> /// <param name="Relative">Whether this is an absolute value or relative to the previous</param> internal void ApplyReverser(int Value, bool Relative) { int a = (int)Handles.Reverser.Driver; int r = Relative ? a + Value : Value; if (r < -1) { r = -1; } if (r > 1) { r = 1; } if (a != r) { Handles.Reverser.Driver = (ReverserPosition)r; if (Plugin != null) { Plugin.UpdateReverser(); } Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // sound if (a == 0 & r != 0) { Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.ReverserOn.Buffer; if (buffer == null) { return; } Vector3 pos = Cars[DriverCar].Sounds.ReverserOn.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } else if (a != 0 & r == 0) { Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.ReverserOff.Buffer; if (buffer == null) { return; } Vector3 pos = Cars[DriverCar].Sounds.ReverserOff.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } }
internal SoundHandleEx PlaySound(int index, double volume, double pitch, bool looped) { if (index < 0 || index >= this.Train.Cars[this.Train.DriverCar].Sounds.Plugin.Length || this.Train.Cars[this.Train.DriverCar].Sounds.Plugin[index].Buffer == null) { return(null); } Sounds.SoundBuffer buffer = this.Train.Cars[this.Train.DriverCar].Sounds.Plugin[index].Buffer; OpenBveApi.Math.Vector3D position = this.Train.Cars[this.Train.DriverCar].Sounds.Plugin[index].Position; Sounds.SoundSource source = Sounds.PlaySound(buffer, pitch, volume, position, this.Train, this.Train.DriverCar, looped); if (this.SoundHandlesCount == this.SoundHandles.Length) { Array.Resize <SoundHandleEx>(ref this.SoundHandles, this.SoundHandles.Length << 1); } this.SoundHandles[this.SoundHandlesCount] = new SoundHandleEx(volume, pitch, source); this.SoundHandlesCount++; return(this.SoundHandles[this.SoundHandlesCount - 1]); }
/// <summary>Closes the left-hand or right-hand doors for the specified train</summary> /// <param name="Train">The train</param> /// <param name="Left">Whether to close the left-hand doors</param> /// <param name="Right">Whether to close the right-hand doors</param> internal static void CloseTrainDoors(Train Train, bool Left, bool Right) { bool sl = false, sr = false; for (int i = 0; i < Train.Cars.Length; i++) { if (Left & Train.Cars[i].Doors[0].AnticipatedOpen) { Train.Cars[i].Doors[0].AnticipatedOpen = false; sl = true; } if (Right & Train.Cars[i].Doors[1].AnticipatedOpen) { Train.Cars[i].Doors[1].AnticipatedOpen = false; sr = true; } } if (sl) { for (int i = 0; i < Train.Cars.Length; i++) { Sounds.SoundBuffer buffer = Train.Cars[i].Doors[0].CloseSound.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[i].Doors[0].CloseSound.Position; Sounds.PlaySound(buffer, Train.Cars[i].Specs.DoorClosePitch, 1.0, pos, Train, i, false); } } } if (sr) { for (int i = 0; i < Train.Cars.Length; i++) { Sounds.SoundBuffer buffer = Train.Cars[i].Doors[1].CloseSound.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[i].Doors[1].CloseSound.Position; Sounds.PlaySound(buffer, Train.Cars[i].Specs.DoorClosePitch, 1.0, pos, Train, i, false); } } } }
internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { if (Direction > 0) { int d = Train.DriverCar; Sounds.SoundBuffer buffer = Train.Cars[d].Sounds.Halt.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[d].Sounds.Halt.Position; if (Train.Specs.PassAlarm == TrainManager.PassAlarmType.Single) { Train.Cars[d].Sounds.Halt.Source = Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, d, false); } else if (Train.Specs.PassAlarm == TrainManager.PassAlarmType.Loop) { Train.Cars[d].Sounds.Halt.Source = Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, d, true); } } this.DontTriggerAnymore = true; } } }
private CarSound(Sounds.SoundBuffer buffer, Sounds.SoundSource source, Vector3 position) { this.Buffer = buffer; this.Source = source; this.Position = position; }
/// <summary>Moves the air brake handle to the specified state</summary> /// <param name="State">The state</param> internal void ApplyAirBrakeHandle(AirBrakeHandleState State) { if (Handles.Brake is AirBrakeHandle) { if ((int)State != Handles.Brake.Driver) { // sound when moved to service if (State == AirBrakeHandleState.Service) { Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.Brake.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // sound if ((int)State < (int)Handles.Brake.Driver) { // brake release if ((int)State > 0) { // brake release (not min) Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // brake min Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if ((int)State > (int)Handles.Brake.Driver) { // brake Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleApply.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // apply Handles.Brake.Driver = (int)State; Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // plugin if (Plugin != null) { Plugin.UpdatePower(); Plugin.UpdateBrake(); } } } }
protected override void Elapse(ElapseData data) { try { double time = data.TotalTime.Milliseconds; Win32VehicleState win32State; win32State.Location = data.Vehicle.Location; win32State.Speed = (float)data.Vehicle.Speed.KilometersPerHour; win32State.Time = (int)Math.Floor(time - 2073600000.0 * Math.Floor(time / 2073600000.0)); win32State.BcPressure = (float)data.Vehicle.BcPressure; win32State.MrPressure = (float)data.Vehicle.MrPressure; win32State.ErPressure = (float)data.Vehicle.ErPressure; win32State.BpPressure = (float)data.Vehicle.BpPressure; win32State.SapPressure = (float)data.Vehicle.SapPressure; win32State.Current = 0.0f; Win32Handles win32Handles; win32Handles.Brake = data.Handles.BrakeNotch; win32Handles.Power = data.Handles.PowerNotch; win32Handles.Reverser = data.Handles.Reverser; win32Handles.ConstantSpeed = data.Handles.ConstSpeed ? ConstSpeedInstructions.Enable : ConstSpeedInstructions.Disable; Win32Elapse(ref win32Handles.Brake, ref win32State.Location, ref base.Panel[0], ref this.Sound[0]); data.Handles.Reverser = win32Handles.Reverser; data.Handles.PowerNotch = win32Handles.Power; data.Handles.BrakeNotch = win32Handles.Brake; if (win32Handles.ConstantSpeed == ConstSpeedInstructions.Enable) { data.Handles.ConstSpeed = true; } else if (win32Handles.ConstantSpeed == ConstSpeedInstructions.Disable) { data.Handles.ConstSpeed = false; } else if (win32Handles.ConstantSpeed != ConstSpeedInstructions.Continue) { this.PluginValid = false; } /* * Process the sound instructions * */ for (int i = 0; i < this.Sound.Length; i++) { if (this.Sound[i] != this.LastSound[i]) { if (this.Sound[i] == SoundInstructions.Stop) { if (i < base.Train.Cars[base.Train.DriverCar].Sounds.Plugin.Length) { Sounds.StopSound(base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source); } } else if (this.Sound[i] > SoundInstructions.Stop & this.Sound[i] <= SoundInstructions.PlayLooping) { if (i < base.Train.Cars[base.Train.DriverCar].Sounds.Plugin.Length) { Sounds.SoundBuffer buffer = base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Buffer; if (buffer != null) { double volume = (double)(this.Sound[i] - SoundInstructions.Stop) / (double)(SoundInstructions.PlayLooping - SoundInstructions.Stop); if (Sounds.IsPlaying(base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source)) { base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source.Volume = volume; } else { base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source = Sounds.PlaySound(buffer, 1.0, volume, base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Position, base.Train, base.Train.DriverCar, true); } } } } else if (this.Sound[i] == SoundInstructions.PlayOnce) { if (i < base.Train.Cars[base.Train.DriverCar].Sounds.Plugin.Length) { Sounds.SoundBuffer buffer = base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Buffer; if (buffer != null) { base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Source = Sounds.PlaySound(buffer, 1.0, 1.0, base.Train.Cars[base.Train.DriverCar].Sounds.Plugin[i].Position, base.Train, base.Train.DriverCar, false); } } this.Sound[i] = SoundInstructions.Continue; } else if (this.Sound[i] != SoundInstructions.Continue) { this.PluginValid = false; } this.LastSound[i] = this.Sound[i]; } else { if ((this.Sound[i] < SoundInstructions.Stop | this.Sound[i] > SoundInstructions.PlayLooping) && this.Sound[i] != SoundInstructions.PlayOnce & this.Sound[i] != SoundInstructions.Continue) { this.PluginValid = false; } } } } catch (Exception ex) { base.LastException = ex; throw; } }
/// <summary>Parses a single XML node into a sound buffer and position reference</summary> /// <param name="node">The node to parse</param> /// <param name="Sound">The car sound</param> /// <param name="Position">The default position of this sound (May be overriden by the node)</param> /// <param name="Radius">The default radius of this sound (May be overriden by the node)</param> private static void ParseNode(XmlNode node, out Sounds.SoundBuffer Sound, ref Vector3 Position, double Radius) { string fileName = null; foreach (XmlNode c in node.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "filename": try { fileName = OpenBveApi.Path.CombineFile(currentPath, c.InnerText); if (!System.IO.File.Exists(fileName)) { //Valid path, but the file does not exist Interface.AddMessage(Interface.MessageType.Error, false, "The sound path " + c.InnerText + " in XML node " + node.Name + " does not exist."); Sound = null; return; } } catch { //Probably invalid filename characters Interface.AddMessage(Interface.MessageType.Error, false, "The sound path " + c.InnerText + " in XML node " + node.Name + " is invalid."); Sound = null; return; } break; case "position": string[] Arguments = c.InnerText.Split(','); double x = 0.0, y = 0.0, z = 0.0; if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[0], out x)) { Interface.AddMessage(Interface.MessageType.Error, false, "Sound radius X " + Arguments[0] + " in XML node " + node.Name + " is invalid."); x = 0.0; } if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[1], out y)) { Interface.AddMessage(Interface.MessageType.Error, false, "Sound radius Y " + Arguments[1] + " in XML node " + node.Name + " is invalid."); y = 0.0; } if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[2], out z)) { Interface.AddMessage(Interface.MessageType.Error, false, "Sound radius Z " + Arguments[2] + " in XML node " + node.Name + " is invalid."); z = 0.0; } Position = new Vector3(x, y, z); break; case "radius": if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out Radius)) { Interface.AddMessage(Interface.MessageType.Error, false, "The sound radius " + c.InnerText + " in XML node " + node.Name + " is invalid."); } break; } } if (fileName == null) { //No valid filename node specified Interface.AddMessage(Interface.MessageType.Error, false, "XML node " + node.Name + " does not point to a valid sound file."); Sound = null; return; } Sound = Sounds.SoundBuffer.TryToLoad(fileName, Radius); }
/// <summary>Moves the air brake handle to the specified state</summary> /// <param name="newState">The state</param> internal void ApplyLocoAirBrakeHandle(AirBrakeHandleState newState) { if (Handles.LocoBrake is LocoAirBrakeHandle) { if ((int)newState != Handles.LocoBrake.Driver) { // sound when moved to service if (newState == AirBrakeHandleState.Service) { Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.Brake.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // sound if ((int)newState < (int)Handles.Brake.Driver) { // brake release if ((int)newState > 0) { // brake release (not min) Sounds.SoundBuffer buffer; if ((Handles.Brake.Driver - (int)newState > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // brake min Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if ((int)newState > (int)Handles.LocoBrake.Driver) { // brake Sounds.SoundBuffer buffer; if (((int)newState - (int)Handles.LocoBrake.Driver > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleApply.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // apply Handles.LocoBrake.Driver = (int)newState; Handles.LocoBrake.Actual = (int)newState; //TODO: FIXME Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // plugin if (Plugin != null) { Plugin.UpdatePower(); Plugin.UpdateBrake(); } } } }
internal static void LeaveCheck(Vector2 Point) { if (!Loading.SimulationSetup) { return; } if (World.CameraMode != CameraViewMode.Interior && World.CameraMode != CameraViewMode.InteriorLookAhead) { return; } TrainManager.Car Car = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar]; int add = Car.CarSections[0].CurrentAdditionalGroup + 1; if (add < Car.CarSections[0].Groups.Length) { TrainManager.TouchElement[] TouchElements = Car.CarSections[0].Groups[add].TouchElements; if (TouchElements != null) { foreach (var TouchElement in TouchElements) { int o = TouchElement.Element.ObjectIndex; ShowObjectSelection(o); } int[] SelectBuffer = new int[2048]; PickPre(SelectBuffer, Point, new Vector2(5)); RenderSceneSelection(); int PickedObjectIndex = PickPost(SelectBuffer); foreach (var TouchElement in TouchElements) { int o = TouchElement.Element.ObjectIndex; HideObjectSelection(o); if (o == PickedObjectIndex) { Car.CarSections[0].CurrentAdditionalGroup = TouchElement.JumpScreenIndex; Car.ChangeCarSection(TrainManager.CarSectionType.Interior); if (TouchElement.SoundIndex >= 0 && TouchElement.SoundIndex < Car.Sounds.Touch.Length) { Sounds.SoundBuffer Buffer = Car.Sounds.Touch[TouchElement.SoundIndex].Buffer; OpenBveApi.Math.Vector3 Position = Car.Sounds.Touch[TouchElement.SoundIndex].Position; Sounds.PlaySound(Buffer, 1.0, 1.0, Position, TrainManager.PlayerTrain, TrainManager.PlayerTrain.DriverCar, false); } } // HACK: Normally terminate the command issued once. if (o == PickedObjectIndex || (PickedObjectIndex != PrePickedObjectIndex && o == PrePickedObjectIndex)) { for (int i = 0; i < Interface.CurrentControls.Length; i++) { if (Interface.CurrentControls[i].Method != Interface.ControlMethod.Touch) { continue; } bool EnableOption = false; for (int j = 0; j < Translations.CommandInfos.Length; j++) { if (Interface.CurrentControls[i].Command == Translations.CommandInfos[j].Command) { EnableOption = Translations.CommandInfos[j].EnableOption; break; } } if (TouchElement.Command == Interface.CurrentControls[i].Command) { if (EnableOption && TouchElement.CommandOption != Interface.CurrentControls[i].Option) { continue; } Interface.CurrentControls[i].AnalogState = 0.0; Interface.CurrentControls[i].DigitalState = Interface.DigitalControlState.Released; MainLoop.RemoveControlRepeat(i); } } } } } } }
/// <summary>Applies the emergency brake</summary> internal void ApplyEmergencyBrake() { // sound if (!Handles.EmergencyBrake.Driver) { Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.BrakeHandleMax.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMax.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } for (int i = 0; i < Cars.Length; i++) { buffer = Cars[DriverCar].Sounds.EmrBrake.Buffer; if (buffer != null) { Vector3 pos = Cars[i].Sounds.EmrBrake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } // apply ApplyNotch(0, !Handles.SingleHandle, Handles.Brake.MaximumNotch, true); ApplyAirBrakeHandle(AirBrakeHandleState.Service); Handles.EmergencyBrake.Driver = true; Handles.HoldBrake.Driver = false; Specs.CurrentConstSpeed = false; if (Handles.EmergencyBrake.Driver) { switch (Handles.EmergencyBrake.OtherHandlesBehaviour) { case EbHandleBehaviour.PowerNeutral: if (!Handles.SingleHandle) { ApplyNotch(0, false, 0, true); } break; case EbHandleBehaviour.ReverserNeutral: ApplyReverser(0, false); break; case EbHandleBehaviour.PowerReverserNeutral: if (!Handles.SingleHandle) { ApplyNotch(0, false, 0, true); } ApplyReverser(0, false); break; } } // plugin if (Plugin == null) { return; } Plugin.UpdatePower(); Plugin.UpdateBrake(); }
/// <param name="SoundBuffer">HACK: Set to a null reference to indicate the train point sound.</param> internal SoundEvent(double TrackPositionDelta, Sounds.SoundBuffer SoundBuffer, bool PlayerTrainOnly, bool Once, bool Dynamic, Vector3 Position, double Speed) { this.TrackPositionDelta = TrackPositionDelta; this.DontTriggerAnymore = false; this.SoundBuffer = SoundBuffer; this.PlayerTrainOnly = PlayerTrainOnly; this.Once = Once; this.Dynamic = Dynamic; this.Position = Position; this.Speed = Speed; }
/// <summary>Applies a power and / or brake notch to this train</summary> /// <param name="PowerValue">The power notch value</param> /// <param name="PowerRelative">Whether this is relative to the current notch</param> /// <param name="BrakeValue">The brake notch value</param> /// <param name="BrakeRelative">Whether this is relative to the current notch</param> /// <param name="IsOverMaxDriverNotch"></param> internal void ApplyNotch(int PowerValue, bool PowerRelative, int BrakeValue, bool BrakeRelative, bool IsOverMaxDriverNotch = false) { // determine notch int p = PowerRelative ? PowerValue + Handles.Power.Driver : PowerValue; if (p < 0) { p = 0; } else if (p > Handles.Power.MaximumNotch) { p = Handles.Power.MaximumNotch; } if (!IsOverMaxDriverNotch && p > Handles.Power.MaximumDriverNotch) { p = Handles.Power.MaximumDriverNotch; } int b = BrakeRelative ? BrakeValue + Handles.Brake.Driver : BrakeValue; if (b < 0) { b = 0; } else if (b > Handles.Brake.MaximumNotch) { b = Handles.Brake.MaximumNotch; } if (!IsOverMaxDriverNotch && b > Handles.Brake.MaximumDriverNotch) { b = Handles.Brake.MaximumDriverNotch; } // power sound if (p < Handles.Power.Driver) { if (p > 0) { // down (not min) Sounds.SoundBuffer buffer; if ((Handles.Power.Driver - p > 2 | Cars[DriverCar].Sounds.PowerHandleFast) && Cars[DriverCar].Sounds.MasterControllerDownFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.MasterControllerDownFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.MasterControllerDown.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerDown.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // min Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.MasterControllerMin.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if (p > Handles.Power.Driver) { if (p < Handles.Power.MaximumDriverNotch) { // up (not max) Sounds.SoundBuffer buffer; if ((Handles.Power.Driver - p > 2 | Cars[DriverCar].Sounds.PowerHandleFast) && Cars[DriverCar].Sounds.MasterControllerUpFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.MasterControllerUpFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.MasterControllerUp.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerUp.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // max Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.MasterControllerMax.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.MasterControllerMax.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } // brake sound if (b < Handles.Brake.Driver) { // brake release Sounds.SoundBuffer buffer = Cars[DriverCar].Sounds.Brake.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } if (b > 0) { // brake release (not min) if ((Handles.Brake.Driver - b > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleReleaseFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleRelease.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } else { // brake min buffer = Cars[DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } } else if (b > Handles.Brake.Driver) { // brake Sounds.SoundBuffer buffer; if ((b - Handles.Brake.Driver > 2 | Cars[DriverCar].Sounds.BrakeHandleFast) && Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer != null) { buffer = Cars[DriverCar].Sounds.BrakeHandleApplyFast.Buffer; } else { buffer = Cars[DriverCar].Sounds.BrakeHandleApply.Buffer; } if (buffer != null) { Vector3 pos = Cars[DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, DriverCar, false); } } // apply notch if (Handles.SingleHandle) { if (b != 0) { p = 0; } } Handles.Power.Driver = p; Handles.Brake.Driver = b; Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // plugin if (Plugin != null) { Plugin.UpdatePower(); Plugin.UpdateBrake(); } }
/// <summary>Updates the brake system for a car within this train</summary> /// <remarks>This must remain a property of the train, for easy access to various base properties</remarks> /// <param name="CarIndex">The induvidual car</param> /// <param name="TimeElapsed">The frame time elapsed</param> /// <param name="DecelerationDueToBrake">The total brake deceleration this car provides</param> /// <param name="DecelerationDueToMotor">The total motor deceleration this car provides</param> private void UpdateBrakeSystem(int CarIndex, double TimeElapsed, out double DecelerationDueToBrake, out double DecelerationDueToMotor) { DecelerationDueToBrake = 0.0; // air compressor if (Cars[CarIndex].CarBrake.brakeType == BrakeType.Main) { if (Cars[CarIndex].CarBrake.airCompressor.Enabled) { if (Cars[CarIndex].CarBrake.mainReservoir.CurrentPressure > Cars[CarIndex].CarBrake.mainReservoir.MaximumPressure) { Cars[CarIndex].CarBrake.airCompressor.Enabled = false; Cars[CarIndex].Sounds.CpLoopStarted = false; Sounds.SoundBuffer buffer = Cars[CarIndex].Sounds.CpEnd.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[CarIndex].Sounds.CpEnd.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, CarIndex, false); } buffer = Cars[CarIndex].Sounds.CpLoop.Buffer; if (buffer != null) { Sounds.StopSound(Cars[CarIndex].Sounds.CpLoop.Source); } } else { Cars[CarIndex].CarBrake.mainReservoir.CurrentPressure += Cars[CarIndex].CarBrake.airCompressor.Rate * TimeElapsed; if (!Cars[CarIndex].Sounds.CpLoopStarted && Game.SecondsSinceMidnight > Cars[CarIndex].Sounds.CpStartTimeStarted + 5.0) { Cars[CarIndex].Sounds.CpLoopStarted = true; Sounds.SoundBuffer buffer = Cars[CarIndex].Sounds.CpLoop.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[CarIndex].Sounds.CpLoop.Position; Cars[CarIndex].Sounds.CpLoop.Source = Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, CarIndex, true); } } } } else { if (Cars[CarIndex].CarBrake.mainReservoir.CurrentPressure < Cars[CarIndex].CarBrake.mainReservoir.MinimumPressure) { Cars[CarIndex].CarBrake.airCompressor.Enabled = true; Cars[CarIndex].Sounds.CpStartTimeStarted = Game.SecondsSinceMidnight; Sounds.SoundBuffer buffer = Cars[CarIndex].Sounds.CpStart.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[CarIndex].Sounds.CpStart.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, CarIndex, false); } } } } if (CarIndex == DriverCar && Handles.HasLocoBrake) { switch (Handles.LocoBrakeType) { case LocoBrakeType.Independant: //With an independant Loco brake, we always want to use this handle Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.LocoBrake, out DecelerationDueToBrake); break; case LocoBrakeType.Combined: if (Handles.LocoBrake is LocoBrakeHandle && Handles.Brake is NotchedHandle) { //Both handles are of the notched type if (Handles.Brake.MaximumNotch == Handles.LocoBrake.MaximumNotch) { //Identical number of notches, so return the handle with the higher setting if (Handles.LocoBrake.Actual >= Handles.Brake.Actual) { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.LocoBrake, out DecelerationDueToBrake); } else { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.Brake, out DecelerationDueToBrake); } } else if (Handles.Brake.MaximumNotch > Handles.LocoBrake.MaximumNotch) { double nc = ((double)Handles.LocoBrake.Actual / Handles.LocoBrake.MaximumNotch) * Handles.Brake.MaximumNotch; if (nc > Handles.Brake.Actual) { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.LocoBrake, out DecelerationDueToBrake); } else { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.Brake, out DecelerationDueToBrake); } } else { double nc = ((double)Handles.Brake.Actual / Handles.Brake.MaximumNotch) * Handles.LocoBrake.MaximumNotch; if (nc > Handles.LocoBrake.Actual) { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.Brake, out DecelerationDueToBrake); } else { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.LocoBrake, out DecelerationDueToBrake); } } } else if (Handles.LocoBrake is LocoAirBrakeHandle && Handles.Brake is AirBrakeHandle) { if (Handles.LocoBrake.Actual < Handles.Brake.Actual) { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.Brake, out DecelerationDueToBrake); } else { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.LocoBrake, out DecelerationDueToBrake); } } else { double p, tp; //Calculate the pressure differentials for the two handles if (Handles.LocoBrake is LocoAirBrakeHandle) { //Air brake handle p = Cars[CarIndex].CarBrake.brakeCylinder.CurrentPressure / Cars[CarIndex].CarBrake.brakeCylinder.ServiceMaximumPressure; tp = (Cars[CarIndex].CarBrake.brakeCylinder.ServiceMaximumPressure / Handles.Brake.MaximumNotch) * Handles.Brake.Actual; } else { //Notched handle p = Cars[CarIndex].CarBrake.brakeCylinder.CurrentPressure / Cars[CarIndex].CarBrake.brakeCylinder.ServiceMaximumPressure; tp = (Cars[CarIndex].CarBrake.brakeCylinder.ServiceMaximumPressure / Handles.LocoBrake.MaximumNotch) * Handles.LocoBrake.Actual; } if (p < tp) { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.Brake, out DecelerationDueToBrake); } else { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.LocoBrake, out DecelerationDueToBrake); } } break; case LocoBrakeType.Blocking: if (Handles.LocoBrake.Actual != 0) { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.LocoBrake, out DecelerationDueToBrake); } else { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.Brake, out DecelerationDueToBrake); } break; } } else { Cars[CarIndex].CarBrake.Update(TimeElapsed, Cars[DriverCar].Specs.CurrentSpeed, Handles.Brake, out DecelerationDueToBrake); } switch (Cars[CarIndex].CarBrake.airSound) { case AirSound.AirZero: { Sounds.SoundBuffer buffer = Cars[CarIndex].Sounds.AirZero.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[CarIndex].Sounds.AirZero.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, CarIndex, false); } break; } case AirSound.Air: { Sounds.SoundBuffer buffer = Cars[CarIndex].Sounds.Air.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[CarIndex].Sounds.Air.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, CarIndex, false); } break; } case AirSound.AirHigh: { Sounds.SoundBuffer buffer = Cars[CarIndex].Sounds.AirHigh.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Cars[CarIndex].Sounds.AirHigh.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, this, CarIndex, false); } break; } } // deceleration provided by motor if (!(Cars[CarIndex].CarBrake is AutomaticAirBrake) && Math.Abs(Cars[CarIndex].Specs.CurrentSpeed) >= Cars[CarIndex].CarBrake.brakeControlSpeed & Handles.Reverser.Actual != 0 & !Handles.EmergencyBrake.Actual) { double f; if (Handles.LocoBrake.Actual != 0 && CarIndex == DriverCar) { f = (double)Handles.LocoBrake.Actual / (double)Handles.Brake.MaximumNotch; } else { f = (double)Handles.Brake.Actual / (double)Handles.Brake.MaximumNotch; } double a = Cars[CarIndex].Specs.MotorDeceleration; DecelerationDueToMotor = f * a; } else { DecelerationDueToMotor = 0.0; } // hold brake Cars[CarIndex].Specs.HoldBrake.Update(ref DecelerationDueToMotor, Handles.HoldBrake.Actual); { // rub sound Sounds.SoundBuffer buffer = Cars[CarIndex].Sounds.Rub.Buffer; if (buffer != null) { double spd = Math.Abs(Cars[CarIndex].Specs.CurrentSpeed); double pitch = 1.0 / (spd + 1.0) + 1.0; double gain = Cars[CarIndex].Derailed ? 0.0 : Cars[CarIndex].CarBrake.brakeCylinder.CurrentPressure / Cars[CarIndex].CarBrake.brakeCylinder.ServiceMaximumPressure; if (spd < 1.38888888888889) { double t = spd * spd; gain *= 1.5552 * t - 0.746496 * spd * t; } else if (spd > 12.5) { double t = spd - 12.5; const double fadefactor = 0.1; gain *= 1.0 / (fadefactor * t * t + 1.0); } if (Sounds.IsPlaying(Cars[CarIndex].Sounds.Rub.Source)) { if (pitch > 0.01 & gain > 0.001) { Cars[CarIndex].Sounds.Rub.Source.Pitch = pitch; Cars[CarIndex].Sounds.Rub.Source.Volume = gain; } else { Sounds.StopSound(Cars[CarIndex].Sounds.Rub.Source); } } else if (pitch > 0.02 & gain > 0.01) { OpenBveApi.Math.Vector3 pos = Cars[CarIndex].Sounds.Rub.Position; Cars[CarIndex].Sounds.Rub.Source = Sounds.PlaySound(buffer, pitch, gain, pos, this, CarIndex, true); } } } }
/// <summary>Is called once a frame to update the station state for the given train</summary> /// <param name="Train">The train</param> /// <param name="TimeElapsed">The frame time elapsed</param> private static void UpdateTrainStation(Train Train, double TimeElapsed) { if (Train.Station >= 0) { int i = Train.Station; int n = Game.Stations[Train.Station].GetStopIndex(Train.Cars.Length); double tf, tb; if (n >= 0) { double p0 = Train.Cars[0].FrontAxle.Follower.TrackPosition - Train.Cars[0].FrontAxle.Position + 0.5 * Train.Cars[0].Length; double p1 = Game.Stations[i].Stops[n].TrackPosition; tf = Game.Stations[i].Stops[n].ForwardTolerance; tb = Game.Stations[i].Stops[n].BackwardTolerance; Train.StationDistanceToStopPoint = p1 - p0; } else { Train.StationDistanceToStopPoint = 0.0; tf = 5.0; tb = 5.0; } if (Train.StationState == TrainStopState.Pending) { Train.StationDepartureSoundPlayed = false; if (Game.StopsAtStation(i, Train)) { Train.StationDepartureSoundPlayed = false; //Check whether all doors are controlled by the driver if (Train.Specs.DoorOpenMode != DoorMode.Manual) { //Check that we are not moving if (Math.Abs(Train.Specs.CurrentAverageSpeed) < 0.1 / 3.6 & Math.Abs(Train.Specs.CurrentAverageAcceleration) < 0.1 / 3.6) { //Check the interlock state for the doors switch (Train.Specs.DoorInterlockState) { case DoorInterlockStates.Unlocked: if (Game.Stations[i].OpenLeftDoors || Game.Stations[i].OpenRightDoors) { AttemptToOpenDoors(Train, i, tb, tf); } break; case DoorInterlockStates.Left: if (Game.Stations[i].OpenLeftDoors && !Game.Stations[i].OpenRightDoors) { AttemptToOpenDoors(Train, i, tb, tf); } break; case DoorInterlockStates.Right: if (!Game.Stations[i].OpenLeftDoors && Game.Stations[i].OpenRightDoors) { AttemptToOpenDoors(Train, i, tb, tf); } break; case DoorInterlockStates.Locked: //All doors are currently locked, do nothing break; } } } // detect arrival if (Train.Specs.CurrentAverageSpeed > -0.277777777777778 & Train.Specs.CurrentAverageSpeed < 0.277777777777778) { bool left, right; if (Game.Stations[i].OpenLeftDoors) { left = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Doors[0].AnticipatedOpen) { left = true; break; } } } else { left = true; } if (Game.Stations[i].OpenRightDoors) { right = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Doors[1].AnticipatedOpen) { right = true; break; } } } else { right = true; } if (left & right) { // arrival Train.StationState = TrainStopState.Boarding; Train.StationAdjust = false; Train.Specs.DoorClosureAttempted = false; Sounds.StopSound(Train.Cars[Train.DriverCar].Sounds.Halt.Source); Sounds.SoundBuffer buffer = Game.Stations[i].ArrivalSoundBuffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Game.Stations[i].SoundOrigin; Sounds.PlaySound(buffer, 1.0, 1.0, pos, false); } Train.StationArrivalTime = Game.SecondsSinceMidnight; Train.StationDepartureTime = Game.Stations[i].DepartureTime - Train.TimetableDelta; if (Train.StationDepartureTime - Game.SecondsSinceMidnight < Game.Stations[i].StopTime) { Train.StationDepartureTime = Game.SecondsSinceMidnight + Game.Stations[i].StopTime; } Train.Passengers.PassengerRatio = Game.Stations[i].PassengerRatio; UpdateTrainMassFromPassengerRatio(Train); if (Train == PlayerTrain) { double early = 0.0; if (Game.Stations[i].ArrivalTime >= 0.0) { early = (Game.Stations[i].ArrivalTime - Train.TimetableDelta) - Train.StationArrivalTime; } string s; if (early < -1.0) { s = Translations.GetInterfaceString("message_station_arrival_late"); } else if (early > 1.0) { s = Translations.GetInterfaceString("message_station_arrival_early"); } else { s = Translations.GetInterfaceString("message_station_arrival"); } System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; TimeSpan a = TimeSpan.FromSeconds(Math.Abs(early)); string b = a.Hours.ToString("00", Culture) + ":" + a.Minutes.ToString("00", Culture) + ":" + a.Seconds.ToString("00", Culture); if (Train.StationDistanceToStopPoint < -0.1) { s += Translations.GetInterfaceString("message_delimiter") + Translations.GetInterfaceString("message_station_overrun"); } else if (Train.StationDistanceToStopPoint > 0.1) { s += Translations.GetInterfaceString("message_delimiter") + Translations.GetInterfaceString("message_station_underrun"); } double d = Math.Abs(Train.StationDistanceToStopPoint); string c = d.ToString("0.0", Culture); if (Game.Stations[i].Type == StationType.Terminal) { s += Translations.GetInterfaceString("message_delimiter") + Translations.GetInterfaceString("message_station_terminal"); } s = s.Replace("[name]", Game.Stations[i].Name); s = s.Replace("[time]", b); s = s.Replace("[difference]", c); Game.AddMessage(s, MessageManager.MessageDependency.StationArrival, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 10.0, null); if (Game.Stations[i].Type == StationType.Normal) { s = Translations.GetInterfaceString("message_station_deadline"); Game.AddMessage(s, MessageManager.MessageDependency.StationDeparture, Interface.GameMode.Normal, MessageColor.White, double.PositiveInfinity, null); } Timetable.UpdateCustomTimetable(Game.Stations[i].TimetableDaytimeTexture, Game.Stations[i].TimetableNighttimeTexture); } // schedule door locks (passengers stuck between the doors) for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Doors.Length; k++) { Train.Cars[j].Doors[k].DoorLockDuration = 0.0; if (Game.Stations[i].OpenLeftDoors & Train.Cars[j].Doors[k].Direction == -1 | Game.Stations[i].OpenRightDoors & Train.Cars[j].Doors[k].Direction == 1) { double p = 0.005 * Game.Stations[i].PassengerRatio * Game.Stations[i].PassengerRatio * Game.Stations[i].PassengerRatio * Game.Stations[i].PassengerRatio; if (Program.RandomNumberGenerator.NextDouble() < p) { /* * -- door lock at state -- * minimum: 0.2 (nearly closed) * maximum: 0.8 (nearly opened) * */ Train.Cars[j].Doors[k].DoorLockState = 0.2 + 0.6 * Program.RandomNumberGenerator.NextDouble(); /* -- waiting time -- * minimum: 2.9 s * maximum: 40.0 s * average: 7.6 s * */ p = Program.RandomNumberGenerator.NextDouble(); Train.Cars[j].Doors[k].DoorLockDuration = (50.0 - 10.0 * p) / (17.0 - 16.0 * p); } } } } } else if (Train.Specs.CurrentAverageSpeed > -0.277777777777778 & Train.Specs.CurrentAverageSpeed < 0.277777777777778) { // correct stop position if (!Train.StationAdjust & (Train.StationDistanceToStopPoint > tb | Train.StationDistanceToStopPoint < -tf)) { Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.Adjust.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.Adjust.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } if (Train == TrainManager.PlayerTrain) { Game.AddMessage(Translations.GetInterfaceString("message_station_correct"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.Orange, Game.SecondsSinceMidnight + 5.0, null); } Train.StationAdjust = true; } } else { Train.StationAdjust = false; } } } } else if (Train.StationState == TrainStopState.Boarding) { for (int j = 0; j < Train.Cars.Length; j++) { if (GetDoorsState(Train, j, Game.Stations[i].OpenLeftDoors, Game.Stations[i].OpenRightDoors) == (TrainDoorState.Opened | TrainDoorState.AllOpened)) { //Check whether all doors are controlled by the driver, and whether this is a non-standard station type //e.g. Change ends if (Train.Specs.DoorCloseMode != DoorMode.Manual & Game.Stations[i].Type == StationType.Normal) { //Check the interlock state for the doors switch (Train.Specs.DoorInterlockState) { case DoorInterlockStates.Unlocked: AttemptToCloseDoors(Train); break; case DoorInterlockStates.Left: if (Game.Stations[i].OpenLeftDoors) { AttemptToCloseDoors(Train); } break; case DoorInterlockStates.Right: if (Game.Stations[i].OpenRightDoors) { AttemptToCloseDoors(Train); } break; case DoorInterlockStates.Locked: //All doors are currently locked, do nothing break; } if (Train.Specs.DoorInterlockState != DoorInterlockStates.Locked & Train.Specs.DoorClosureAttempted) { if (Game.Stations[i].OpenLeftDoors && !Train.Cars[j].Doors[0].AnticipatedReopen && Program.RandomNumberGenerator.NextDouble() < Game.Stations[i].ReopenDoor) { Train.Cars[j].Doors[0].ReopenLimit = Program.RandomNumberGenerator.Next(1, Game.Stations[i].ReopenStationLimit); Train.Cars[j].Doors[0].ReopenCounter = 0; Train.Cars[j].Doors[0].InterferingObjectRate = Program.RandomNumberGenerator.Next(1, Game.Stations[i].MaxInterferingObjectRate) * 0.01; if (Train.Cars[j].Doors[0].InterferingObjectRate * Train.Specs.DoorWidth >= Train.Specs.DoorMaxTolerance) { Train.Cars[j].Doors[0].AnticipatedReopen = true; } } if (Game.Stations[i].OpenRightDoors && !Train.Cars[j].Doors[1].AnticipatedReopen && Program.RandomNumberGenerator.NextDouble() < Game.Stations[i].ReopenDoor) { Train.Cars[j].Doors[1].ReopenLimit = Program.RandomNumberGenerator.Next(1, Game.Stations[i].ReopenStationLimit); Train.Cars[j].Doors[1].ReopenCounter = 0; Train.Cars[j].Doors[1].InterferingObjectRate = Program.RandomNumberGenerator.Next(1, Game.Stations[i].MaxInterferingObjectRate) * 0.01; if (Train.Cars[j].Doors[1].InterferingObjectRate * Train.Specs.DoorWidth >= Train.Specs.DoorMaxTolerance) { Train.Cars[j].Doors[1].AnticipatedReopen = true; } } } } } } // detect departure bool left, right; if (!Game.Stations[i].OpenLeftDoors & !Game.Stations[i].OpenRightDoors) { left = true; right = true; } else { if (Game.Stations[i].OpenLeftDoors) { left = false; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Doors.Length; k++) { if (Train.Cars[j].Doors[k].State != 0.0) { left = true; break; } } if (left) { break; } } } else { left = false; } if (Game.Stations[i].OpenRightDoors) { right = false; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Doors.Length; k++) { if (Train.Cars[j].Doors[k].State != 0.0) { right = true; break; } } if (right) { break; } } } else { right = false; } } // departure sound if (!Train.StationDepartureSoundPlayed) { Sounds.SoundBuffer buffer = Game.Stations[i].DepartureSoundBuffer; if (buffer != null) { double dur = Sounds.GetDuration(buffer); if (Game.SecondsSinceMidnight >= Train.StationDepartureTime - dur) { Sounds.PlaySound(buffer, 1.0, 1.0, Game.Stations[i].SoundOrigin, false); Train.StationDepartureSoundPlayed = true; } } } for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Doors[0].AnticipatedReopen && Train.Cars[j].Doors[0].State == Train.Cars[j].Doors[0].InterferingObjectRate) { if (Train.Cars[j].Doors[0].NextReopenTime == 0.0) { Train.Cars[j].Doors[0].NextReopenTime = Game.SecondsSinceMidnight + Game.Stations[i].InterferenceInDoor; } else if (Train.Cars[j].Doors[0].ReopenCounter < Train.Cars[j].Doors[0].ReopenLimit) { if (Game.SecondsSinceMidnight >= Train.Cars[j].Doors[0].NextReopenTime) { OpenTrainDoors(Train, j, true, false); } } else { Train.Cars[j].Doors[0].AnticipatedReopen = false; } } if (Train.Cars[j].Doors[1].AnticipatedReopen && Train.Cars[j].Doors[1].State == Train.Cars[j].Doors[1].InterferingObjectRate) { if (Train.Cars[j].Doors[1].NextReopenTime == 0.0) { Train.Cars[j].Doors[1].NextReopenTime = Game.SecondsSinceMidnight + Game.Stations[i].InterferenceInDoor; } else if (Train.Cars[j].Doors[1].ReopenCounter < Train.Cars[j].Doors[1].ReopenLimit) { if (Game.SecondsSinceMidnight >= Train.Cars[j].Doors[1].NextReopenTime) { OpenTrainDoors(Train, j, false, true); } } else { Train.Cars[j].Doors[1].AnticipatedReopen = false; } } } TrainDoorState doorState = GetDoorsState(Train, Game.Stations[i].OpenLeftDoors, Game.Stations[i].OpenRightDoors); if (Train.Specs.DoorCloseMode == DoorMode.Manual || doorState == TrainDoorState.None || doorState == (TrainDoorState.Closed | TrainDoorState.AllClosed)) { if (left | right) { // departure message if (Game.SecondsSinceMidnight > Train.StationDepartureTime && (Game.Stations[i].Type != StationType.Terminal || Train != PlayerTrain)) { Train.StationState = TrainStopState.Completed; if (Train == PlayerTrain & Game.Stations[i].Type == StationType.Normal) { if (!Game.Stations[i].OpenLeftDoors & !Game.Stations[i].OpenRightDoors | Train.Specs.DoorCloseMode != DoorMode.Manual) { Game.AddMessage(Translations.GetInterfaceString("message_station_depart"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 5.0, null); } else { Game.AddMessage(Translations.GetInterfaceString("message_station_depart_closedoors"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 5.0, null); } } else if (Game.Stations[i].Type == StationType.ChangeEnds) { JumpTrain(Train, i + 1); } } if (Interface.CurrentOptions.LoadingSway) { // passengers boarding for (int j = 0; j < Train.Cars.Length; j++) { double r = 2.0 * Game.Stations[i].PassengerRatio * TimeElapsed; if (r >= Program.RandomNumberGenerator.NextDouble()) { int d = (int)Math.Floor(Program.RandomNumberGenerator.NextDouble() * (double)Train.Cars[j].Doors.Length); if (Train.Cars[j].Doors[d].State == 1.0) { Train.Cars[j].Specs.CurrentRollShakeDirection += (double)Train.Cars[j].Doors[d].Direction; } } } } } else { Train.StationState = TrainStopState.Completed; if (Train == PlayerTrain & Game.Stations[i].Type == StationType.Normal) { Game.AddMessage(Translations.GetInterfaceString("message_station_depart"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 5.0, null); } } } } } else { if (Train.StationState != TrainStopState.Jumping) { Train.StationState = TrainStopState.Pending; } } // automatically close doors if (Train.Specs.DoorCloseMode != DoorMode.Manual & Train.Specs.DoorInterlockState != DoorInterlockStates.Locked & !Train.Specs.DoorClosureAttempted) { if (Train.Station == -1 | Train.StationState == TrainStopState.Completed) { if ((GetDoorsState(Train, true, true) & TrainDoorState.AllClosed) == 0) { CloseTrainDoors(Train, true, true); Train.Specs.DoorClosureAttempted = true; } } } }
/// <summary>Is called once a frame, to update the door states of the specified train</summary> /// <param name="Train">The train</param> /// <param name="TimeElapsed">The frame time elapsed</param> private static void UpdateTrainDoors(Train Train, double TimeElapsed) { OpenBveApi.Runtime.DoorStates oldState = OpenBveApi.Runtime.DoorStates.None; OpenBveApi.Runtime.DoorStates newState = OpenBveApi.Runtime.DoorStates.None; for (int i = 0; i < Train.Cars.Length; i++) { bool ld = Train.Cars[i].Doors[0].AnticipatedOpen; bool rd = Train.Cars[i].Doors[1].AnticipatedOpen; double os = Train.Cars[i].Specs.DoorOpenFrequency; double cs = Train.Cars[i].Specs.DoorCloseFrequency; for (int j = 0; j < Train.Cars[i].Doors.Length; j++) { if (Train.Cars[i].Doors[j].Direction == -1 | Train.Cars[i].Doors[j].Direction == 1) { bool shouldBeOpen = Train.Cars[i].Doors[j].Direction == -1 ? ld : rd; if (Train.Cars[i].Doors[j].State > 0.0) { if (Train.Cars[i].Doors[j].Direction == -1) { oldState |= OpenBveApi.Runtime.DoorStates.Left; } else { oldState |= OpenBveApi.Runtime.DoorStates.Right; } } if (shouldBeOpen) { // open Train.Cars[i].Doors[j].State += os * TimeElapsed; if (Train.Cars[i].Doors[j].State > 1.0) { Train.Cars[i].Doors[j].State = 1.0; } } else { // close if (Train.Cars[i].Doors[j].DoorLockDuration > 0.0) { if (Train.Cars[i].Doors[j].State > Train.Cars[i].Doors[j].DoorLockState) { Train.Cars[i].Doors[j].State -= cs * TimeElapsed; } if (Train.Cars[i].Doors[j].State < Train.Cars[i].Doors[j].DoorLockState) { Train.Cars[i].Doors[j].State = Train.Cars[i].Doors[j].DoorLockState; } Train.Cars[i].Doors[j].DoorLockDuration -= TimeElapsed; if (Train.Cars[i].Doors[j].DoorLockDuration < 0.0) { Train.Cars[i].Doors[j].DoorLockDuration = 0.0; } } else { Train.Cars[i].Doors[j].State -= cs * TimeElapsed; } if (Train.Cars[i].Doors[j].AnticipatedReopen && Train.Cars[i].Doors[j].State < Train.Cars[i].Doors[j].InterferingObjectRate) { Train.Cars[i].Doors[j].State = Train.Cars[i].Doors[j].InterferingObjectRate; } if (Train.Cars[i].Doors[j].State < 0.0) { Train.Cars[i].Doors[j].State = 0.0; } } if (Train.Cars[i].Doors[j].State > 0.0) { if (Train.Cars[i].Doors[j].Direction == -1) { newState |= OpenBveApi.Runtime.DoorStates.Left; } else { newState |= OpenBveApi.Runtime.DoorStates.Right; } } } } } if (oldState != OpenBveApi.Runtime.DoorStates.None & newState == OpenBveApi.Runtime.DoorStates.None) { Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.PilotLampOn.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.PilotLampOn.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else if (oldState == OpenBveApi.Runtime.DoorStates.None & newState != OpenBveApi.Runtime.DoorStates.None) { Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.PilotLampOff.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.PilotLampOff.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } if (oldState != newState) { if (Train.Plugin != null) { Train.Plugin.DoorChange(oldState, newState); } } }
// apply notch internal static void ApplyNotch(Train Train, int PowerValue, bool PowerRelative, int BrakeValue, bool BrakeRelative) { // determine notch int p = PowerRelative ? PowerValue + Train.Specs.CurrentPowerNotch.Driver : PowerValue; if (p < 0) { p = 0; } else if (p > Train.Specs.MaximumPowerNotch) { p = Train.Specs.MaximumPowerNotch; } int b = BrakeRelative ? BrakeValue + Train.Specs.CurrentBrakeNotch.Driver : BrakeValue; if (b < 0) { b = 0; } else if (b > Train.Specs.MaximumBrakeNotch) { b = Train.Specs.MaximumBrakeNotch; } // power sound if (p < Train.Specs.CurrentPowerNotch.Driver) { if (p > 0) { // down (not min) Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerDown.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerDown.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else { // min Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerMin.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } } else if (p > Train.Specs.CurrentPowerNotch.Driver) { if (p < Train.Specs.MaximumPowerNotch) { // up (not max) Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerUp.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerUp.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else { // max Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.MasterControllerMax.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.MasterControllerMax.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } } // brake sound if (b < Train.Specs.CurrentBrakeNotch.Driver) { // brake release Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.Brake.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.Brake.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } if (b > 0) { // brake release (not min) buffer = Train.Cars[Train.DriverCar].Sounds.BrakeHandleRelease.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.BrakeHandleRelease.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } else { // brake min buffer = Train.Cars[Train.DriverCar].Sounds.BrakeHandleMin.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.BrakeHandleMin.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } } else if (b > Train.Specs.CurrentBrakeNotch.Driver) { // brake Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.BrakeHandleApply.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.BrakeHandleApply.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } } // apply notch if (Train.Specs.SingleHandle) { if (b != 0) { p = 0; } } Train.Specs.CurrentPowerNotch.Driver = p; Train.Specs.CurrentBrakeNotch.Driver = b; Game.AddBlackBoxEntry(Game.BlackBoxEventToken.None); // plugin if (Train.Plugin != null) { Train.Plugin.UpdatePower(); Train.Plugin.UpdateBrake(); } }