// --- constructors --- /// <summary>Creates a new sound source.</summary> /// <param name="buffer">The sound buffer.</param> /// <param name="radius">The effective sound radius.</param> /// <param name="pitch">The pitch change factor.</param> /// <param name="volume">The volume change factor.</param> /// <param name="position">The position. If a train and car are specified, the position is relative to the car, otherwise absolute.</param> /// <param name="train">The train this sound source is attached to, or a null reference.</param> /// <param name="car">The car this sound source is attached to, or a null reference.</param> /// <param name="looped">Whether this sound source plays in a loop.</param> internal SoundSource(SoundBuffer buffer, double radius, double pitch, double volume, OpenBveApi.Math.Vector3D position, TrainManager.Train train, int car, bool looped) { this.Buffer = buffer; this.Radius = radius; this.Pitch = pitch; this.Volume = volume; this.Position = position; this.Train = train; this.Car = car; this.Looped = looped; this.State = SoundSourceState.PlayPending; this.OpenAlSourceName = 0; }
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; } } }
internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { if (Direction < 0) { Train.StationFrontCar = true; } else if (Direction > 0) { Train.StationFrontCar = false; if (Train == TrainManager.PlayerTrain) { Timetable.UpdateCustomTimetable(Game.Stations[this.StationIndex].TimetableDaytimeTexture, Game.Stations[this.StationIndex].TimetableNighttimeTexture); } } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { if (Direction < 0) { Train.Station = this.StationIndex; Train.StationRearCar = true; if (Train.NextStopSkipped != TrainManager.StopSkipMode.None) { Train.LastStation = this.StationIndex; } Train.NextStopSkipped = TrainManager.StopSkipMode.None; } else if (Direction > 0) { if (Train.Station == StationIndex) { if (Train == TrainManager.PlayerTrain) { if (Game.PlayerStopsAtStation(StationIndex) & TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Pending) { string s = Interface.GetInterfaceString("message_station_passed"); s = s.Replace("[name]", Game.Stations[StationIndex].Name); Game.AddMessage(s, MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.Orange, Game.SecondsSinceMidnight + 10.0, null); } else if (Game.PlayerStopsAtStation(StationIndex) & TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Boarding) { string s = Interface.GetInterfaceString("message_station_passed_boarding"); s = s.Replace("[name]", Game.Stations[StationIndex].Name); Game.AddMessage(s, MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.Red, Game.SecondsSinceMidnight + 10.0, null); } } Train.Station = -1; Train.StationRearCar = false; Train.StationState = TrainManager.TrainStopState.Pending; int d = Train.DriverCar; Sounds.StopSound(Train.Cars[d].Sounds.Halt.Source); } } } }
internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (Train != null) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { if (Direction < 0) { if (this.NextSectionIndex >= 0) { Game.Sections[this.NextSectionIndex].TrainReachedStopPoint = false; } UpdateFrontBackward(Train, true); } else if (Direction > 0) { UpdateFrontForward(Train, true, true); } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { if (Direction < 0) { UpdateRearBackward(Train, true); } else if (Direction > 0) { if (this.PreviousSectionIndex >= 0) { Game.Sections[this.PreviousSectionIndex].TrainReachedStopPoint = false; } UpdateRearForward(Train, true); } } } }
/// <summary>Loads the specified plugin for the specified train.</summary> /// <param name="train">The train to attach the plugin to.</param> /// <param name="pluginFile">The file to the plugin.</param> /// <param name="trainFolder">The train folder.</param> /// <returns>Whether the plugin was loaded successfully.</returns> private static bool LoadPlugin(TrainManager.Train train, string pluginFile, string trainFolder) { string pluginTitle = System.IO.Path.GetFileName(pluginFile); if (!System.IO.File.Exists(pluginFile)) { Debug.AddMessage(Debug.MessageType.Error, true, "The train plugin " + pluginTitle + " could not be found."); return(false); } /* * Unload plugin if already loaded. * */ if (train.Plugin != null) { UnloadPlugin(train); } /* * Prepare initialization data for the plugin. * */ BrakeTypes brakeType = (BrakeTypes)train.Cars[train.DriverCar].Specs.BrakeType; int brakeNotches; int powerNotches; bool hasHoldBrake; if (brakeType == BrakeTypes.AutomaticAirBrake) { brakeNotches = 2; powerNotches = train.Specs.MaximumPowerNotch; hasHoldBrake = false; } else { brakeNotches = train.Specs.MaximumBrakeNotch + (train.Specs.HasHoldBrake ? 1 : 0); powerNotches = train.Specs.MaximumPowerNotch; hasHoldBrake = train.Specs.HasHoldBrake; } int cars = train.Cars.Length; VehicleSpecs specs = new VehicleSpecs(powerNotches, brakeType, brakeNotches, hasHoldBrake, cars); InitializationModes mode = (InitializationModes)Game.TrainStart; /* * Check if the plugin is a .NET plugin. * */ Assembly assembly; try { assembly = Assembly.LoadFile(pluginFile); } catch (BadImageFormatException) { assembly = null; } catch (Exception ex) { Debug.AddMessage(Debug.MessageType.Error, false, "The train plugin " + pluginTitle + " could not be loaded due to the following exception: " + ex.Message); return(false); } if (assembly != null) { Type[] types; try { types = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { foreach (Exception e in ex.LoaderExceptions) { Debug.AddMessage(Debug.MessageType.Error, false, "The train plugin " + pluginTitle + " raised an exception on loading: " + e.Message); } return(false); } foreach (Type type in types) { if (typeof(IRuntime).IsAssignableFrom(type)) { IRuntime api = assembly.CreateInstance(type.FullName) as IRuntime; train.Plugin = new NetPlugin(pluginFile, trainFolder, api, train); if (train.Plugin.Load(specs, mode)) { return(true); } train.Plugin = null; return(false); } } Debug.AddMessage(Debug.MessageType.Error, false, "The train plugin " + pluginTitle + " does not export a train interface and therefore cannot be used with openBVE."); return(false); } /* * Check if the plugin is a Win32 plugin. * */ try { if (!CheckWin32Header(pluginFile)) { Debug.AddMessage(Debug.MessageType.Error, false, "The train plugin " + pluginTitle + " is of an unsupported binary format and therefore cannot be used with openBVE."); return(false); } } catch (Exception ex) { Debug.AddMessage(Debug.MessageType.Error, false, "The train plugin " + pluginTitle + " could not be read due to the following reason: " + ex.Message); return(false); } if (!Program.CurrentlyRunningOnWindows | IntPtr.Size != 4) { Debug.AddMessage(Debug.MessageType.Warning, false, "The train plugin " + pluginTitle + " can only be used on 32-bit Microsoft Windows or compatible."); return(false); } train.Plugin = new Win32Plugin(pluginFile, train); if (train.Plugin.Load(specs, mode)) { return(true); } train.Plugin = null; return(false); }
internal abstract void Trigger(TrainManager.Train Train, double TimeElapsed);
internal override void Update(double TimeElapsed, bool ForceUpdate) { const double extraRadius = 10.0; double z = Object.TranslateZFunction == null ? 0.0 : Object.TranslateZFunction.LastResult; double pa = TrackPosition + z - Radius - extraRadius; double pb = TrackPosition + z + Radius + extraRadius; double ta = World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z - World.BackgroundImageDistance - World.ExtraViewingDistance; double tb = World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z + World.BackgroundImageDistance + World.ExtraViewingDistance; bool visible = pb >= ta & pa <= tb; if (visible | ForceUpdate) { if (Object.SecondsSinceLastUpdate >= Object.RefreshRate | ForceUpdate) { double timeDelta = Object.SecondsSinceLastUpdate + TimeElapsed; Object.SecondsSinceLastUpdate = 0.0; TrainManager.Train train = null; double trainDistance = double.MaxValue; for (int j = 0; j < TrainManager.Trains.Length; j++) { if (TrainManager.Trains[j].State == TrainManager.TrainState.Available) { double distance; if (TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition < TrackPosition) { distance = TrackPosition - TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition; } else if (TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition > TrackPosition) { distance = TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition - TrackPosition; } else { distance = 0; } if (distance < trainDistance) { train = TrainManager.Trains[j]; trainDistance = distance; } } } Object.Update(false, train, train == null ? 0 : train.DriverCar, SectionIndex, TrackPosition, Position, Direction, Up, Side, false, true, true, timeDelta, true); if (this.Object.CurrentState != this.lastState && Loading.SimulationSetup) { if (this.SingleBuffer && this.Buffers[0] != null) { switch (this.Object.CurrentState) { case -1: if (this.PlayOnHide) { this.Source = Sounds.PlaySound(this.Buffers[0], this.currentPitch, this.currentVolume, this.Position, false); } break; case 0: if (this.PlayOnShow || this.lastState != -1) { this.Source = Sounds.PlaySound(this.Buffers[0], this.currentPitch, this.currentVolume, this.Position, false); } break; default: this.Source = Sounds.PlaySound(this.Buffers[0], this.currentPitch, this.currentVolume, this.Position, false); break; } } else { int bufferIndex = this.Object.CurrentState + 1; if (bufferIndex < this.Buffers.Length && this.Buffers[bufferIndex] != null) { switch (bufferIndex) { case 0: if (this.PlayOnHide) { this.Source = Sounds.PlaySound(this.Buffers[bufferIndex], this.currentPitch, this.currentVolume, this.Position, false); } break; case 1: if (this.PlayOnShow || this.lastState != -1) { this.Source = Sounds.PlaySound(this.Buffers[bufferIndex], this.currentPitch, this.currentVolume, this.Position, false); } break; default: this.Source = Sounds.PlaySound(this.Buffers[bufferIndex], this.currentPitch, this.currentVolume, this.Position, false); break; } } } } } else { Object.SecondsSinceLastUpdate += TimeElapsed; } if (!Visible) { Renderer.ShowObject(Object.ObjectIndex, Renderer.ObjectType.Dynamic); Visible = true; } } else { Object.SecondsSinceLastUpdate += TimeElapsed; if (Visible) { Renderer.HideObject(Object.ObjectIndex); Visible = false; } } this.lastState = this.Object.CurrentState; }
/// <summary>Gets the signal data for a plugin.</summary> /// <param name="train">The train.</param> /// <param name="section">The absolute section index, referencing Game.Sections[].</param> /// <returns>The signal data.</returns> internal static OpenBveApi.Runtime.SignalData GetPluginSignal(TrainManager.Train train, int section) { if (Sections[section].Exists(train)) { int aspect; if (Sections[section].IsFree(train)) { if (Sections[section].Type == SectionType.IndexBased) { if (section + 1 < Sections.Length) { int value = Sections[section + 1].FreeSections; if (value == -1) { value = Sections[section].Aspects.Length - 1; } else { value++; if (value >= Sections[section].Aspects.Length) { value = Sections[section].Aspects.Length - 1; } if (value < 0) { value = 0; } } aspect = Sections[section].Aspects[value].Number; } else { aspect = Sections[section].Aspects[Sections[section].Aspects.Length - 1].Number; } } else { aspect = Sections[section].Aspects[Sections[section].Aspects.Length - 1].Number; if (section < Sections.Length - 1) { int value = Sections[section + 1].Aspects[Sections[section + 1].CurrentAspect].Number; for (int i = 0; i < Sections[section].Aspects.Length; i++) { if (Sections[section].Aspects[i].Number > value) { aspect = Sections[section].Aspects[i].Number; break; } } } } } else { aspect = Sections[section].Aspects[Sections[section].CurrentAspect].Number; } double position = train.Cars[0].FrontAxle.Follower.TrackPosition - train.Cars[0].FrontAxle.Position + 0.5 * train.Cars[0].Length; double distance = Sections[section].TrackPosition - position; return(new OpenBveApi.Runtime.SignalData(aspect, distance)); } else { int aspect = Sections[section].Aspects[Sections[section].CurrentAspect].Number; double position = train.Cars[0].FrontAxle.Follower.TrackPosition - train.Cars[0].FrontAxle.Position + 0.5 * train.Cars[0].Length; double distance = Sections[section].TrackPosition - position; return(new OpenBveApi.Runtime.SignalData(aspect, distance)); } }
internal static void PlaySound(int SoundBufferIndex, TrainManager.Train Train, int CarIndex, World.Vector3D Position, Importance Important, bool Looped) { int a = -1; PlaySound(ref a, false, SoundBufferIndex, Train, CarIndex, Position, Important, Looped, 1.0, 1.0); }
internal static void ParseExtensionsConfig(string filePath, Encoding encoding, out UnifiedObject[] carObjects, out UnifiedObject[] bogieObjects, out double[] axleLocations, out TrainManager.Train train, bool loadObjects) { CultureInfo Culture = CultureInfo.InvariantCulture; carObjects = new UnifiedObject[] { }; bogieObjects = new UnifiedObject[] { }; axleLocations = new double[] { }; train = new TrainManager.Train(); if (!System.IO.File.Exists(filePath)) { return; } train.Cars = new TrainManager.Car[] { }; bool[] carObjectsReversed = new bool[train.Cars.Length]; bool[] bogieObjectsReversed = new bool[train.Cars.Length * 2]; bool[] carsDefined = new bool[train.Cars.Length]; bool[] bogiesDefined = new bool[train.Cars.Length * 2]; axleLocations = new double[train.Cars.Length * 2]; string trainPath = System.IO.Path.GetDirectoryName(filePath); System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.InvariantCulture; TextEncoding.Encoding newEncoding = TextEncoding.GetEncodingFromFile(filePath); if (newEncoding != TextEncoding.Encoding.Unknown) { switch (newEncoding) { case TextEncoding.Encoding.Utf7: encoding = Encoding.UTF7; break; case TextEncoding.Encoding.Utf8: encoding = Encoding.UTF8; break; case TextEncoding.Encoding.Utf16Le: encoding = Encoding.Unicode; break; case TextEncoding.Encoding.Utf16Be: encoding = Encoding.BigEndianUnicode; break; case TextEncoding.Encoding.Utf32Le: encoding = Encoding.UTF32; break; case TextEncoding.Encoding.Utf32Be: encoding = Encoding.GetEncoding(12001); break; case TextEncoding.Encoding.Shift_JIS: encoding = Encoding.GetEncoding(932); break; } } string[] lines = System.IO.File.ReadAllLines(filePath, encoding); for (int i = 0; i < lines.Length; i++) { int j = lines[i].IndexOf(';'); if (j >= 0) { lines[i] = lines[i].Substring(0, j).Trim(new char[] { }); } else { lines[i] = lines[i].Trim(new char[] { }); } } for (int i = 0; i < lines.Length; i++) { if (lines[i].Length != 0) { switch (lines[i].ToLowerInvariant()) { case "[exterior]": // exterior i++; while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal)) { if (lines[i].Length != 0) { int j = lines[i].IndexOf("=", StringComparison.Ordinal); if (j >= 0) { string a = lines[i].Substring(0, j).TrimEnd(new char[] { }); string b = lines[i].Substring(j + 1).TrimStart(new char[] { }); int n; if (int.TryParse(a, System.Globalization.NumberStyles.Integer, culture, out n)) { if (n >= 0) { if (n >= train.Cars.Length) { Array.Resize(ref train.Cars, n + 1); train.Cars[n] = new TrainManager.Car(train); Array.Resize(ref carObjects, n + 1); Array.Resize(ref bogieObjects, (n + 1) * 2); Array.Resize(ref carObjectsReversed, n + 1); Array.Resize(ref bogieObjectsReversed, (n + 1) * 2); Array.Resize(ref carsDefined, n + 1); Array.Resize(ref bogiesDefined, (n + 1) * 2); Array.Resize(ref axleLocations, (n + 1) * 2); } if (Path.ContainsInvalidChars(b)) { Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(culture) + " in file " + filePath); } else { string file = OpenBveApi.Path.CombineFile(trainPath, b); if (System.IO.File.Exists(file)) { if (loadObjects) { carObjects[n] = ObjectManager.LoadObject(file, encoding, false); } } else { Interface.AddMessage(MessageType.Error, true, "The car object " + file + " does not exist at line " + (i + 1).ToString(culture) + " in file " + filePath); } } } else { Interface.AddMessage(MessageType.Error, false, "The car index " + a + " does not reference an existing car at line " + (i + 1).ToString(culture) + " in file " + filePath); } } else { Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(culture) + " in file " + filePath); } } else { Interface.AddMessage(MessageType.Error, false, "Invalid statement " + lines[i] + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath); } } i++; } i--; break; default: if (lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal)) { // car string t = lines[i].Substring(4, lines[i].Length - 5); int n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, culture, out n)) { if (n >= 0) { if (n >= train.Cars.Length) { Array.Resize(ref train.Cars, n + 1); train.Cars[n] = new TrainManager.Car(train); Array.Resize(ref carObjects, n + 1); Array.Resize(ref bogieObjects, (n + 1) * 2); Array.Resize(ref carObjectsReversed, n + 1); Array.Resize(ref bogieObjectsReversed, (n + 1) * 2); Array.Resize(ref carsDefined, n + 1); Array.Resize(ref bogiesDefined, (n + 1) * 2); Array.Resize(ref axleLocations, (n + 1) * 2); } if (carsDefined[n]) { Interface.AddMessage(MessageType.Error, false, "Car " + n.ToString(culture) + " has already been declared at line " + (i + 1).ToString(culture) + " in file " + filePath); } carsDefined[n] = true; i++; while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal)) { if (lines[i].Length != 0) { int j = lines[i].IndexOf("=", StringComparison.Ordinal); if (j >= 0) { string a = lines[i].Substring(0, j).TrimEnd(new char[] { }); string b = lines[i].Substring(j + 1).TrimStart(new char[] { }); switch (a.ToLowerInvariant()) { case "object": if (string.IsNullOrEmpty(b)) { Interface.AddMessage(MessageType.Error, true, "An empty car object was supplied at line " + (i + 1).ToString(culture) + " in file " + filePath); break; } if (Path.ContainsInvalidChars(b)) { Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(culture) + " in file " + filePath); } else { string file = OpenBveApi.Path.CombineFile(trainPath, b); if (System.IO.File.Exists(file)) { if (loadObjects) { carObjects[n] = ObjectManager.LoadObject(file, encoding, false); } } else { Interface.AddMessage(MessageType.Error, true, "The car object " + file + " does not exist at line " + (i + 1).ToString(culture) + " in file " + filePath); } } break; case "length": { double m; if (double.TryParse(b, System.Globalization.NumberStyles.Float, culture, out m)) { if (m > 0.0) { train.Cars[n].Length = m; } else { Interface.AddMessage(MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(culture) + " in file " + filePath); } } else { Interface.AddMessage(MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(culture) + " in file " + filePath); } } break; case "reversed": carObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase); break; case "axles": int k = b.IndexOf(','); if (k >= 0) { string c = b.Substring(0, k).TrimEnd(new char[] { }); string d = b.Substring(k + 1).TrimStart(new char[] { }); double rear, front; if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear)) { Interface.AddMessage(MessageType.Error, false, "Rear is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath); } else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out front)) { Interface.AddMessage(MessageType.Error, false, "Front is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath); } else if (rear >= front) { Interface.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath); } else { if (n == 0) { axleLocations[n] = rear; axleLocations[n + 1] = front; } else { axleLocations[n * 2] = rear; axleLocations[n * 2 + 1] = front; } } } else { Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + filePath); } break; default: Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath); break; } } else { Interface.AddMessage(MessageType.Error, false, "Invalid statement " + lines[i] + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath); } } i++; } i--; } else { Interface.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(culture) + " in file " + filePath); } } else { Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(culture) + " in file " + filePath); } } else if (lines[i].StartsWith("[bogie", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal)) { // car string t = lines[i].Substring(6, lines[i].Length - 7); int n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, culture, out n)) { if (n >= train.Cars.Length * 2) { Array.Resize(ref train.Cars, n / 2 + 1); if (n == 0) { train.Cars[0] = new TrainManager.Car(train); Array.Resize(ref axleLocations, 2); } else { train.Cars[n / 2] = new TrainManager.Car(train); Array.Resize(ref axleLocations, ((n / 2) + 1) * 2); } Array.Resize(ref carObjects, n / 2 + 1); Array.Resize(ref bogieObjects, n + 2); Array.Resize(ref carObjectsReversed, n / 2 + 1); Array.Resize(ref bogieObjectsReversed, n + 2); Array.Resize(ref carsDefined, n / 2 + 1); Array.Resize(ref bogiesDefined, n + 2); } if (n > bogiesDefined.Length - 1) { continue; } if (bogiesDefined[n]) { Interface.AddMessage(MessageType.Error, false, "Bogie " + n.ToString(culture) + " has already been declared at line " + (i + 1).ToString(culture) + " in file " + filePath); } bogiesDefined[n] = true; //Assuming that there are two bogies per car if (n >= 0 & n < train.Cars.Length * 2) { i++; while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal)) { if (lines[i].Length != 0) { int j = lines[i].IndexOf("=", StringComparison.Ordinal); if (j >= 0) { string a = lines[i].Substring(0, j).TrimEnd(new char[] { }); string b = lines[i].Substring(j + 1).TrimStart(new char[] { }); switch (a.ToLowerInvariant()) { case "object": if (Path.ContainsInvalidChars(b)) { Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(culture) + " in file " + filePath); } else { if (string.IsNullOrEmpty(b)) { Interface.AddMessage(MessageType.Error, true, "An empty bogie object was supplied at line " + (i + 1).ToString(culture) + " in file " + filePath); break; } string file = OpenBveApi.Path.CombineFile(trainPath, b); if (System.IO.File.Exists(file)) { if (loadObjects) { bogieObjects[n] = ObjectManager.LoadObject(file, encoding, false); } } else { Interface.AddMessage(MessageType.Error, true, "The bogie object " + file + " does not exist at line " + (i + 1).ToString(culture) + " in file " + filePath); } } break; case "length": { Interface.AddMessage(MessageType.Error, false, "A defined length is not supported for bogies at line " + (i + 1).ToString(culture) + " in file " + filePath); } break; case "reversed": bogieObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase); break; case "axles": //Axles aren't used in bogie positioning, just in rotation break; default: Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath); break; } } else { Interface.AddMessage(MessageType.Error, false, "Invalid statement " + lines[i] + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath); } } i++; } i--; } else { Interface.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(culture) + " in file " + filePath); } } else { Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(culture) + " in file " + filePath); } } else if (lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal)) { i++; while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal)) { /* * Coupler statments are currently not supported in Object Viewer */ i++; } i--; } else { // default if (lines.Length == 1 && encoding.Equals(Encoding.Unicode)) { /* * If only one line, there's a good possibility that our file is NOT Unicode at all * and that the misdetection has turned it into garbage * * Try again with ASCII instead */ ParseExtensionsConfig(filePath, Encoding.GetEncoding(1252), out carObjects, out bogieObjects, out axleLocations, out train, loadObjects); return; } Interface.AddMessage(MessageType.Error, false, "Invalid statement " + lines[i] + " encountered at line " + (i + 1).ToString(culture) + " in file " + filePath); } break; } } } // check for car objects and reverse if necessary int carObjectsCount = 0; for (int i = 0; i < train.Cars.Length; i++) { if (carObjects[i] != null) { carObjectsCount++; if (carObjectsReversed[i] && loadObjects) { if (carObjects[i] is StaticObject) { StaticObject obj = (StaticObject)carObjects[i]; obj.ApplyScale(-1.0, 1.0, -1.0); } else if (carObjects[i] is AnimatedObjectCollection) { AnimatedObjectCollection obj = (AnimatedObjectCollection)carObjects[i]; for (int j = 0; j < obj.Objects.Length; j++) { for (int h = 0; h < obj.Objects[j].States.Length; h++) { obj.Objects[j].States[h].Prototype.ApplyScale(-1.0, 1.0, -1.0); Matrix4D t = obj.Objects[j].States[h].Translation; t.Row3.X *= -1.0f; t.Row3.Z *= -1.0f; obj.Objects[j].States[h].Translation = t; } obj.Objects[j].TranslateXDirection.X *= -1.0; obj.Objects[j].TranslateXDirection.Z *= -1.0; obj.Objects[j].TranslateYDirection.X *= -1.0; obj.Objects[j].TranslateYDirection.Z *= -1.0; obj.Objects[j].TranslateZDirection.X *= -1.0; obj.Objects[j].TranslateZDirection.Z *= -1.0; } } else { throw new NotImplementedException(); } } } } //Check for bogie objects and reverse if necessary..... int bogieObjectsCount = 0; for (int i = 0; i < train.Cars.Length * 2; i++) { if (bogieObjects[i] != null) { bogieObjectsCount++; if (bogieObjectsReversed[i] && loadObjects) { if (bogieObjects[i] is StaticObject) { StaticObject obj = (StaticObject)bogieObjects[i]; obj.ApplyScale(-1.0, 1.0, -1.0); } else if (bogieObjects[i] is AnimatedObjectCollection) { AnimatedObjectCollection obj = (AnimatedObjectCollection)bogieObjects[i]; for (int j = 0; j < obj.Objects.Length; j++) { for (int h = 0; h < obj.Objects[j].States.Length; h++) { obj.Objects[j].States[h].Prototype.ApplyScale(-1.0, 1.0, -1.0); Matrix4D t = obj.Objects[j].States[h].Translation; t.Row3.X *= -1.0f; t.Row3.Z *= -1.0f; obj.Objects[j].States[h].Translation = t; } obj.Objects[j].TranslateXDirection.X *= -1.0; obj.Objects[j].TranslateXDirection.Z *= -1.0; obj.Objects[j].TranslateYDirection.X *= -1.0; obj.Objects[j].TranslateYDirection.Z *= -1.0; obj.Objects[j].TranslateZDirection.X *= -1.0; obj.Objects[j].TranslateZDirection.Z *= -1.0; } } else { throw new NotImplementedException(); } } } } if (carObjectsCount > 0 & carObjectsCount < train.Cars.Length) { Interface.AddMessage(MessageType.Warning, false, "An incomplete set of exterior objects was provided in file " + filePath); } if (bogieObjectsCount > 0 & bogieObjectsCount < train.Cars.Length * 2) { Interface.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + filePath); } }
internal override void Update(double TimeElapsed, bool ForceUpdate) { const double extraRadius = 10.0; double z = Object.TranslateZFunction == null ? 0.0 : Object.TranslateZFunction.LastResult; double pa = TrackPosition + z - Radius - extraRadius; double pb = TrackPosition + z + Radius + extraRadius; double ta = World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z - World.BackgroundImageDistance - World.ExtraViewingDistance; double tb = World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z + World.BackgroundImageDistance + World.ExtraViewingDistance; bool visible = pb >= ta & pa <= tb; if (visible | ForceUpdate) { if (Object.SecondsSinceLastUpdate >= Object.RefreshRate | ForceUpdate) { double timeDelta = Object.SecondsSinceLastUpdate + TimeElapsed; Object.SecondsSinceLastUpdate = 0.0; TrainManager.Train train = null; double trainDistance = double.MaxValue; for (int j = 0; j < TrainManager.Trains.Length; j++) { if (TrainManager.Trains[j].State == TrainManager.TrainState.Available) { double distance; if (TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition < TrackPosition) { distance = TrackPosition - TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition; } else if (TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition > TrackPosition) { distance = TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition - TrackPosition; } else { distance = 0; } if (distance < trainDistance) { train = TrainManager.Trains[j]; trainDistance = distance; } } } Object.Update(false, train, train == null ? 0 : train.DriverCar, SectionIndex, TrackPosition, Position, Direction, Up, Side, false, true, true, timeDelta, true); } else { Object.SecondsSinceLastUpdate += TimeElapsed; } if (!Visible) { Renderer.ShowObject(Object.ObjectIndex, ObjectType.Dynamic); Visible = true; } } else { Object.SecondsSinceLastUpdate += TimeElapsed; if (Visible) { Renderer.HideObject(Object.ObjectIndex); Visible = false; } } }
internal DriverBody(TrainManager.Train train) { this.Train = train; }
// parse extensions config internal static void ParseExtensionsConfig(string TrainPath, System.Text.Encoding Encoding, ref UnifiedObject[] CarObjects, ref UnifiedObject[] BogieObjects, TrainManager.Train Train, bool LoadObjects) { bool[] CarObjectsReversed = new bool[Train.Cars.Length]; bool[] BogieObjectsReversed = new bool[Train.Cars.Length * 2]; bool[] CarsDefined = new bool[Train.Cars.Length]; bool[] BogiesDefined = new bool[Train.Cars.Length * 2]; System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; string FileName = OpenBveApi.Path.CombineFile(TrainPath, "extensions.cfg"); if (System.IO.File.Exists(FileName)) { TextEncoding.Encoding newEncoding = TextEncoding.GetEncodingFromFile(FileName); if (newEncoding != TextEncoding.Encoding.Unknown) { switch (newEncoding) { case TextEncoding.Encoding.Utf7: Encoding = System.Text.Encoding.UTF7; break; case TextEncoding.Encoding.Utf8: Encoding = System.Text.Encoding.UTF8; break; case TextEncoding.Encoding.Utf16Le: Encoding = System.Text.Encoding.Unicode; break; case TextEncoding.Encoding.Utf16Be: Encoding = System.Text.Encoding.BigEndianUnicode; break; case TextEncoding.Encoding.Utf32Le: Encoding = System.Text.Encoding.UTF32; break; case TextEncoding.Encoding.Utf32Be: Encoding = System.Text.Encoding.GetEncoding(12001); break; case TextEncoding.Encoding.Shift_JIS: Encoding = System.Text.Encoding.GetEncoding(932); break; } } string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding); for (int i = 0; i < Lines.Length; i++) { int j = Lines[i].IndexOf(';'); if (j >= 0) { Lines[i] = Lines[i].Substring(0, j).Trim(); } else { Lines[i] = Lines[i].Trim(); } } for (int i = 0; i < Lines.Length; i++) { if (Lines[i].Length != 0) { switch (Lines[i].ToLowerInvariant()) { case "[exterior]": // exterior i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal)) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j >= 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); int n; if (int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out n)) { if (n >= 0 & n < Train.Cars.Length) { if (Path.ContainsInvalidChars(b)) { Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { string File = OpenBveApi.Path.CombineFile(TrainPath, b); if (System.IO.File.Exists(File)) { if (LoadObjects) { CarObjects[n] = ObjectManager.LoadObject(File, Encoding, false); } } else { Interface.AddMessage(MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } } else { Interface.AddMessage(MessageType.Error, false, "The car index " + a + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else { Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else { Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } i++; } i--; break; default: if (Lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal)) { // car string t = Lines[i].Substring(4, Lines[i].Length - 5); int n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n)) { if (n >= 0 & n < Train.Cars.Length) { if (CarsDefined[n]) { Interface.AddMessage(MessageType.Error, false, "Car " + n.ToString(Culture) + " has already been declared at line " + (i + 1).ToString(Culture) + " in file " + FileName); } CarsDefined[n] = true; bool DefinedLength = false; bool DefinedAxles = false; i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal)) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j >= 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); switch (a.ToLowerInvariant()) { case "object": if (string.IsNullOrEmpty(b)) { Interface.AddMessage(MessageType.Error, true, "An empty car object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } if (Path.ContainsInvalidChars(b)) { Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { string File = OpenBveApi.Path.CombineFile(TrainPath, b); if (System.IO.File.Exists(File)) { if (LoadObjects) { CarObjects[n] = ObjectManager.LoadObject(File, Encoding, false); } } else { Interface.AddMessage(MessageType.Error, true, "The car object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "length": { double m; if (double.TryParse(b, System.Globalization.NumberStyles.Float, Culture, out m)) { if (m > 0.0) { Train.Cars[n].Length = m; Train.Cars[n].BeaconReceiverPosition = 0.5 * m; DefinedLength = true; } else { Interface.AddMessage(MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else { Interface.AddMessage(MessageType.Error, false, "Value is expected to be a positive floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "axles": { int k = b.IndexOf(','); if (k >= 0) { string c = b.Substring(0, k).TrimEnd(); string d = b.Substring(k + 1).TrimStart(); double rear, front; if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear)) { Interface.AddMessage(MessageType.Error, false, "Rear is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out front)) { Interface.AddMessage(MessageType.Error, false, "Front is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (rear >= front) { Interface.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { Train.Cars[n].RearAxle.Position = rear; Train.Cars[n].FrontAxle.Position = front; DefinedAxles = true; } } else { Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "reversed": CarObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase); break; case "loadingsway": Train.Cars[n].EnableLoadingSway = b.Equals("true", StringComparison.OrdinalIgnoreCase); break; default: Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } } else { Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } i++; } i--; if (DefinedLength & !DefinedAxles) { double AxleDistance = 0.4 * Train.Cars[n].Length; Train.Cars[n].RearAxle.Position = -AxleDistance; Train.Cars[n].FrontAxle.Position = AxleDistance; } } else { Interface.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else { Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else if (Lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal)) { // coupler string t = Lines[i].Substring(8, Lines[i].Length - 9); int n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n)) { if (n >= 0 & n < Train.Couplers.Length) { i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal)) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j >= 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); switch (a.ToLowerInvariant()) { case "distances": { int k = b.IndexOf(','); if (k >= 0) { string c = b.Substring(0, k).TrimEnd(); string d = b.Substring(k + 1).TrimStart(); double min, max; if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out min)) { Interface.AddMessage(MessageType.Error, false, "Minimum is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out max)) { Interface.AddMessage(MessageType.Error, false, "Maximum is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (min > max) { Interface.AddMessage(MessageType.Error, false, "Minimum is expected to be less than Maximum in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { Train.Couplers[n].MinimumDistanceBetweenCars = min; Train.Couplers[n].MaximumDistanceBetweenCars = max; } } else { Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; default: Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } } else { Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } i++; } i--; } else { Interface.AddMessage(MessageType.Error, false, "The coupler index " + t + " does not reference an existing coupler at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else { Interface.AddMessage(MessageType.Error, false, "The coupler index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else if (Lines[i].StartsWith("[bogie", StringComparison.OrdinalIgnoreCase) & Lines[i].EndsWith("]", StringComparison.Ordinal)) { // car string t = Lines[i].Substring(6, Lines[i].Length - 7); int n; if (int.TryParse(t, System.Globalization.NumberStyles.Integer, Culture, out n)) { if (n > BogiesDefined.Length - 1) { continue; } if (BogiesDefined[n]) { Interface.AddMessage(MessageType.Error, false, "Bogie " + n.ToString(Culture) + " has already been declared at line " + (i + 1).ToString(Culture) + " in file " + FileName); } BogiesDefined[n] = true; //Assuming that there are two bogies per car bool IsOdd = (n % 2 != 0); int CarIndex = n / 2; if (n >= 0 & n < Train.Cars.Length * 2) { bool DefinedAxles = false; i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal) & !Lines[i].EndsWith("]", StringComparison.Ordinal)) { if (Lines[i].Length != 0) { int j = Lines[i].IndexOf("=", StringComparison.Ordinal); if (j >= 0) { string a = Lines[i].Substring(0, j).TrimEnd(); string b = Lines[i].Substring(j + 1).TrimStart(); switch (a.ToLowerInvariant()) { case "object": if (Path.ContainsInvalidChars(b)) { Interface.AddMessage(MessageType.Error, false, "File contains illegal characters at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { if (string.IsNullOrEmpty(b)) { Interface.AddMessage(MessageType.Error, true, "An empty bogie object was supplied at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } string File = OpenBveApi.Path.CombineFile(TrainPath, b); if (System.IO.File.Exists(File)) { if (LoadObjects) { BogieObjects[n] = ObjectManager.LoadObject(File, Encoding, false); } } else { Interface.AddMessage(MessageType.Error, true, "The bogie object " + File + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "length": { Interface.AddMessage(MessageType.Error, false, "A defined length is not supported for bogies at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; case "axles": { int k = b.IndexOf(','); if (k >= 0) { string c = b.Substring(0, k).TrimEnd(); string d = b.Substring(k + 1).TrimStart(); double rear, front; if (!double.TryParse(c, System.Globalization.NumberStyles.Float, Culture, out rear)) { Interface.AddMessage(MessageType.Error, false, "Rear is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (!double.TryParse(d, System.Globalization.NumberStyles.Float, Culture, out front)) { Interface.AddMessage(MessageType.Error, false, "Front is expected to be a floating-point number in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else if (rear >= front) { Interface.AddMessage(MessageType.Error, false, "Rear is expected to be less than Front in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } else { if (IsOdd) { Train.Cars[CarIndex].FrontBogie.RearAxle.Position = rear; Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = front; } else { Train.Cars[CarIndex].RearBogie.RearAxle.Position = rear; Train.Cars[CarIndex].RearBogie.FrontAxle.Position = front; } DefinedAxles = true; } } else { Interface.AddMessage(MessageType.Error, false, "An argument-separating comma is expected in " + a + " at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } break; case "reversed": BogieObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase); break; default: Interface.AddMessage(MessageType.Warning, false, "Unsupported key-value pair " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); break; } } else { Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } i++; } i--; if (!DefinedAxles) { if (IsOdd) { double AxleDistance = 0.4 * Train.Cars[CarIndex].FrontBogie.Length; Train.Cars[CarIndex].FrontBogie.RearAxle.Position = -AxleDistance; Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = AxleDistance; } else { double AxleDistance = 0.4 * Train.Cars[CarIndex].RearBogie.Length; Train.Cars[CarIndex].RearBogie.RearAxle.Position = -AxleDistance; Train.Cars[CarIndex].RearBogie.FrontAxle.Position = AxleDistance; } } } else { Interface.AddMessage(MessageType.Error, false, "The car index " + t + " does not reference an existing car at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else { Interface.AddMessage(MessageType.Error, false, "The car index is expected to be an integer at line " + (i + 1).ToString(Culture) + " in file " + FileName); } } else { // default if (Lines.Length == 1 && Encoding.Equals(Encoding.Unicode)) { /* * If only one line, there's a good possibility that our file is NOT Unicode at all * and that the misdetection has turned it into garbage * * Try again with ASCII instead */ ParseExtensionsConfig(TrainPath, Encoding.GetEncoding(1252), ref CarObjects, ref BogieObjects, Train, LoadObjects); return; } Interface.AddMessage(MessageType.Error, false, "Invalid statement " + Lines[i] + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName); } break; } } } // check for car objects and reverse if necessary int carObjects = 0; for (int i = 0; i < Train.Cars.Length; i++) { if (CarObjects[i] != null) { carObjects++; if (CarObjectsReversed[i] && LoadObjects) { { // reverse axle positions double temp = Train.Cars[i].FrontAxle.Position; Train.Cars[i].FrontAxle.Position = -Train.Cars[i].RearAxle.Position; Train.Cars[i].RearAxle.Position = -temp; } if (CarObjects[i] is StaticObject) { StaticObject obj = (StaticObject)CarObjects[i]; obj.ApplyScale(-1.0, 1.0, -1.0); } else if (CarObjects[i] is ObjectManager.AnimatedObjectCollection) { ObjectManager.AnimatedObjectCollection obj = (ObjectManager.AnimatedObjectCollection)CarObjects[i]; for (int j = 0; j < obj.Objects.Length; j++) { for (int h = 0; h < obj.Objects[j].States.Length; h++) { if (obj.Objects[j].States[h].Object == null) { continue; //object failed to load? } obj.Objects[j].States[h].Object.ApplyScale(-1.0, 1.0, -1.0); obj.Objects[j].States[h].Position.X *= -1.0; obj.Objects[j].States[h].Position.Z *= -1.0; } obj.Objects[j].TranslateXDirection.X *= -1.0; obj.Objects[j].TranslateXDirection.Z *= -1.0; obj.Objects[j].TranslateYDirection.X *= -1.0; obj.Objects[j].TranslateYDirection.Z *= -1.0; obj.Objects[j].TranslateZDirection.X *= -1.0; obj.Objects[j].TranslateZDirection.Z *= -1.0; } } else { throw new NotImplementedException(); } } } } //Check for bogie objects and reverse if necessary..... int bogieObjects = 0; for (int i = 0; i < Train.Cars.Length * 2; i++) { bool IsOdd = (i % 2 != 0); int CarIndex = i / 2; if (BogieObjects[i] != null) { bogieObjects++; if (BogieObjectsReversed[i] && LoadObjects) { { // reverse axle positions if (IsOdd) { double temp = Train.Cars[CarIndex].FrontBogie.FrontAxle.Position; Train.Cars[CarIndex].FrontBogie.FrontAxle.Position = -Train.Cars[CarIndex].FrontBogie.RearAxle.Position; Train.Cars[CarIndex].FrontBogie.RearAxle.Position = -temp; } else { double temp = Train.Cars[CarIndex].RearBogie.FrontAxle.Position; Train.Cars[CarIndex].RearBogie.FrontAxle.Position = -Train.Cars[CarIndex].RearBogie.RearAxle.Position; Train.Cars[CarIndex].RearBogie.RearAxle.Position = -temp; } } if (BogieObjects[i] is StaticObject) { StaticObject obj = (StaticObject)BogieObjects[i]; obj.ApplyScale(-1.0, 1.0, -1.0); } else if (BogieObjects[i] is ObjectManager.AnimatedObjectCollection) { ObjectManager.AnimatedObjectCollection obj = (ObjectManager.AnimatedObjectCollection)BogieObjects[i]; for (int j = 0; j < obj.Objects.Length; j++) { for (int h = 0; h < obj.Objects[j].States.Length; h++) { if (obj.Objects[j].States[h].Object == null) { continue; //object failed to load? } obj.Objects[j].States[h].Object.ApplyScale(-1.0, 1.0, -1.0); obj.Objects[j].States[h].Position.X *= -1.0; obj.Objects[j].States[h].Position.Z *= -1.0; } obj.Objects[j].TranslateXDirection.X *= -1.0; obj.Objects[j].TranslateXDirection.Z *= -1.0; obj.Objects[j].TranslateYDirection.X *= -1.0; obj.Objects[j].TranslateYDirection.Z *= -1.0; obj.Objects[j].TranslateZDirection.X *= -1.0; obj.Objects[j].TranslateZDirection.Z *= -1.0; } } else { throw new NotImplementedException(); } } } } if (carObjects > 0 & carObjects < Train.Cars.Length) { Interface.AddMessage(MessageType.Warning, false, "An incomplete set of exterior objects was provided in file " + FileName); } if (bogieObjects > 0 & bogieObjects < Train.Cars.Length * 2) { Interface.AddMessage(MessageType.Warning, false, "An incomplete set of bogie objects was provided in file " + FileName); } } }
/// <summary>Plays a car sound.</summary> /// <param name="sound">The car sound.</param> /// <param name="pitch">The pitch change factor.</param> /// <param name="volume">The volume change factor.</param> /// <param name="train">The train the sound is attached to.</param> /// <param name="car">The car in the train the sound is attached to.</param> /// <param name="looped">Whether to play the sound in a loop.</param> /// <returns>The sound source.</returns> internal static void PlayCarSound(TrainManager.CarSound sound, double pitch, double volume, TrainManager.Train train, int car, bool looped) { if (sound.Buffer == null) { return; } if (train == null) { throw new InvalidDataException("A train and car must be specified"); } sound.Source = PlaySound(sound.Buffer, pitch, volume, sound.Position, train, car, looped); }
internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (TriggerType == EventTriggerType.TrainFront) { if (Direction < 0) { Train.StationFrontCar = false; if (Train.Handles.Reverser.Actual == TrainManager.ReverserPosition.Forwards && Train.Handles.Power.Driver != 0 && !Game.MinimalisticSimulation && StationIndex == Train.Station) { //Our reverser and power are in F, but we are rolling backwards //Leave the station index alone, and we won't trigger again when we actually move forwards return; } Train.Station = -1; } else if (Direction > 0) { if (Train.Station == StationIndex || Train.NextStopSkipped != TrainManager.StopSkipMode.None) { return; } Train.Station = StationIndex; Train.StationFrontCar = true; Train.StationState = TrainManager.TrainStopState.Pending; Train.LastStation = this.StationIndex; } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { if (Direction < 0) { Train.StationRearCar = false; } else { Train.StationRearCar = true; } } }
/// <summary>Updates the specified signal section</summary> /// <param name="SectionIndex">The index of the section to update</param> internal static void UpdateSection(int SectionIndex) { if (SectionIndex >= Sections.Length || Sections == null) { return; } // preparations int zeroaspect; bool settored = false; if (Sections[SectionIndex].Type == SectionType.ValueBased) { // value-based zeroaspect = 0; for (int i = 1; i < Sections[SectionIndex].Aspects.Length; i++) { if (Sections[SectionIndex].Aspects[i].Number < Sections[SectionIndex].Aspects[zeroaspect].Number) { zeroaspect = i; } } } else { // index-based zeroaspect = 0; } // hold station departure signal at red int d = Sections[SectionIndex].StationIndex; if (d >= 0) { // look for train in previous blocks int l = Sections[SectionIndex].PreviousSection; TrainManager.Train train = null; while (true) { if (l >= 0) { train = Sections[l].GetFirstTrain(false); if (train != null) { break; } l = Sections[l].PreviousSection; } else { break; } } if (train == null) { double b = -double.MaxValue; for (int i = 0; i < TrainManager.Trains.Length; i++) { if (TrainManager.Trains[i].State == TrainManager.TrainState.Available) { if (TrainManager.Trains[i].TimetableDelta > b) { b = TrainManager.Trains[i].TimetableDelta; train = TrainManager.Trains[i]; } } } } // set to red where applicable if (train != null) { if (!Sections[SectionIndex].TrainReachedStopPoint) { if (train.Station == d) { int c = GetStopIndex(d, train.Cars.Length); if (c >= 0) { double p0 = train.Cars[0].FrontAxle.Follower.TrackPosition - train.Cars[0].FrontAxle.Position + 0.5 * train.Cars[0].Length; double p1 = Stations[d].Stops[c].TrackPosition - Stations[d].Stops[c].BackwardTolerance; if (p0 >= p1) { Sections[SectionIndex].TrainReachedStopPoint = true; } } else { Sections[SectionIndex].TrainReachedStopPoint = true; } } } double t = -15.0; if (Stations[d].DepartureTime >= 0.0) { t = Stations[d].DepartureTime - 15.0; } else if (Stations[d].ArrivalTime >= 0.0) { t = Stations[d].ArrivalTime; } if (train == TrainManager.PlayerTrain & Stations[d].StationType != StationType.Normal & Stations[d].DepartureTime < 0.0) { settored = true; } else if (t >= 0.0 & SecondsSinceMidnight < t - train.TimetableDelta) { settored = true; } else if (!Sections[SectionIndex].TrainReachedStopPoint) { settored = true; } } else if (Stations[d].StationType != StationType.Normal) { settored = true; } } // train in block if (!Sections[SectionIndex].IsFree()) { settored = true; } // free sections int newaspect = -1; if (settored) { Sections[SectionIndex].FreeSections = 0; newaspect = zeroaspect; } else { int n = Sections[SectionIndex].NextSection; if (n >= 0) { if (Sections[n].FreeSections == -1) { Sections[SectionIndex].FreeSections = -1; } else { Sections[SectionIndex].FreeSections = Sections[n].FreeSections + 1; } } else { Sections[SectionIndex].FreeSections = -1; } } // change aspect if (newaspect == -1) { if (Sections[SectionIndex].Type == SectionType.ValueBased) { // value-based int n = Sections[SectionIndex].NextSection; int a = Sections[SectionIndex].Aspects[Sections[SectionIndex].Aspects.Length - 1].Number; if (n >= 0 && Sections[n].CurrentAspect >= 0) { a = Sections[n].Aspects[Sections[n].CurrentAspect].Number; } for (int i = Sections[SectionIndex].Aspects.Length - 1; i >= 0; i--) { if (Sections[SectionIndex].Aspects[i].Number > a) { newaspect = i; } } if (newaspect == -1) { newaspect = Sections[SectionIndex].Aspects.Length - 1; } } else { // index-based if (Sections[SectionIndex].FreeSections >= 0 & Sections[SectionIndex].FreeSections < Sections[SectionIndex].Aspects.Length) { newaspect = Sections[SectionIndex].FreeSections; } else { newaspect = Sections[SectionIndex].Aspects.Length - 1; } } } // apply new aspect Sections[SectionIndex].CurrentAspect = newaspect; // update previous section if (Sections[SectionIndex].PreviousSection >= 0) { UpdateSection(Sections[SectionIndex].PreviousSection); } }
internal static void PlaySound(ref int SoundSourceIndex, int SoundBufferIndex, TrainManager.Train Train, int CarIndex, World.Vector3D Position, Importance Important, bool Looped, double Pitch, double Gain) { PlaySound(ref SoundSourceIndex, true, SoundBufferIndex, Train, CarIndex, Position, Important, Looped, Pitch, Gain); }
/// <summary>Plays a sound.</summary> /// <param name="buffer">The sound buffer.</param> /// <param name="pitch">The pitch change factor.</param> /// <param name="volume">The volume change factor.</param> /// <param name="position">The position. If a train and car are specified, the position is relative to the car, otherwise absolute.</param> /// <param name="train">The train the sound is attached to, or a null reference.</param> /// <param name="car">The car in the train the sound is attached to.</param> /// <param name="looped">Whether to play the sound in a loop.</param> /// <returns>The sound source.</returns> internal static SoundSource PlaySound(SoundBuffer buffer, double pitch, double volume, OpenBveApi.Math.Vector3D position, TrainManager.Train train, int car, bool looped) { if (Sources.Length == SourceCount) { Array.Resize <SoundSource>(ref Sources, Sources.Length << 1); } Sources[SourceCount] = new SoundSource(buffer, buffer.Radius, pitch, volume, position, train, car, looped); SourceCount++; return(Sources[SourceCount - 1]); }
private static void PlaySound(ref int SoundSourceIndex, bool ReturnHandle, int SoundBufferIndex, TrainManager.Train Train, int CarIndex, World.Vector3D Position, Importance Important, bool Looped, double Pitch, double Gain) { if (OpenAlContext != ContextHandle.Zero) { if (Game.MinimalisticSimulation & Important == Importance.DontCare | SoundBufferIndex == -1) { return; } if (SoundSourceIndex >= 0) { StopSound(ref SoundSourceIndex); } int i; for (i = 0; i < SoundSources.Length; i++) { if (SoundSources[i] == null) { break; } } if (i >= SoundSources.Length) { Array.Resize <SoundSource>(ref SoundSources, SoundSources.Length << 1); } SoundSources[i] = new SoundSource(); SoundSources[i].Position = Position; SoundSources[i].OpenAlPosition = new float[] { 0.0f, 0.0f, 0.0f }; SoundSources[i].OpenAlVelocity = new float[] { 0.0f, 0.0f, 0.0f }; SoundSources[i].SoundBufferIndex = SoundBufferIndex; SoundSources[i].Radius = SoundBuffers[SoundBufferIndex].Radius; SoundSources[i].Pitch = (float)Pitch; SoundSources[i].Gain = (float)Gain; SoundSources[i].Looped = Looped; SoundSources[i].Suppressed = true; SoundSources[i].FinishedPlaying = false; SoundSources[i].Train = Train; SoundSources[i].CarIndex = CarIndex; SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(0, false); SoundSources[i].HasHandle = ReturnHandle; SoundSourceIndex = i; } }
#pragma warning restore 0649 public override void Update(double TimeElapsed, bool ForceUpdate) { const double extraRadius = 10.0; double z = Object.TranslateZFunction == null ? 0.0 : Object.TranslateZFunction.LastResult; double pa = TrackPosition + z - Radius - extraRadius; double pb = TrackPosition + z + Radius + extraRadius; double ta = World.CameraTrackFollower.TrackPosition + Camera.CurrentAlignment.Position.Z - Backgrounds.BackgroundImageDistance - World.ExtraViewingDistance; double tb = World.CameraTrackFollower.TrackPosition + Camera.CurrentAlignment.Position.Z + Backgrounds.BackgroundImageDistance + World.ExtraViewingDistance; bool visible = pb >= ta & pa <= tb; if (visible | ForceUpdate) { if (Object.SecondsSinceLastUpdate >= Object.RefreshRate | ForceUpdate) { double timeDelta = Object.SecondsSinceLastUpdate + TimeElapsed; Object.SecondsSinceLastUpdate = 0.0; TrainManager.Train train = null; double trainDistance = double.MaxValue; for (int j = 0; j < TrainManager.Trains.Length; j++) { if (TrainManager.Trains[j].State == TrainState.Available) { double distance; if (TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition < TrackPosition) { distance = TrackPosition - TrainManager.Trains[j].Cars[0].FrontAxle.Follower.TrackPosition; } else if (TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition > TrackPosition) { distance = TrainManager.Trains[j].Cars[TrainManager.Trains[j].Cars.Length - 1].RearAxle.Follower.TrackPosition - TrackPosition; } else { distance = 0; } if (distance < trainDistance) { train = TrainManager.Trains[j]; trainDistance = distance; } } } if (Visible) { //Calculate the distance travelled double delta = UpdateTrackFollowerScript(false, train, train == null ? 0 : train.DriverCar, SectionIndex, TrackPosition, Position, true, timeDelta); //Update the front and rear axle track followers FrontAxleFollower.Update((TrackPosition + FrontAxlePosition) + delta, true, true); RearAxleFollower.Update((TrackPosition + RearAxlePosition) + delta, true, true); //Update the base object position FrontAxleFollower.UpdateWorldCoordinates(false); RearAxleFollower.UpdateWorldCoordinates(false); UpdateObjectPosition(); } //Update the actual animated object- This must be done last in case the user has used Translation or Rotation Object.Update(false, train, train == null ? 0 : train.DriverCar, SectionIndex, FrontAxleFollower.TrackPosition, FrontAxleFollower.WorldPosition, Direction, Up, Side, false, true, true, timeDelta, true); } else { Object.SecondsSinceLastUpdate += TimeElapsed; } if (!Visible) { Renderer.ShowObject(Object.ObjectIndex, ObjectType.Dynamic); Visible = true; } } else { Object.SecondsSinceLastUpdate += TimeElapsed; if (Visible) { Renderer.HideObject(ref ObjectManager.Objects[Object.ObjectIndex]); Visible = false; } } }
private void ApplyTrain() { lock (Program.LockObj) { Program.TrainManager.Trains = new TrainBase[] { }; if (checkBoxEnableTrain.Checked) { Array.Resize(ref Program.TrainManager.Trains, 1); TrainManager.Train Train = new TrainManager.Train { State = TrainState.Available }; Array.Resize(ref Train.Cars, (int)numericUpDownCars.Value); for (int i = 0; i < Train.Cars.Length; i++) { Train.Cars[i] = new CarBase(Train, i); Train.Cars[i].CurrentSpeed = (int)numericUpDownSpeed.Value / 3.6; Train.Cars[i].Specs = new CarPhysics { PerceivedSpeed = (int)numericUpDownSpeed.Value / 3.6, Acceleration = (int)numericUpDownAccel.Value / 3.6 }; if (checkBoxAirBrake.Checked) { Train.Cars[i].CarBrake = new AutomaticAirBrake(EletropneumaticBrakeType.None, Train.Handles.EmergencyBrake, Train.Handles.Reverser, true, 0.0, 0.0, new AccelerationCurve[] {}); } else { Train.Cars[i].CarBrake = new ElectromagneticStraightAirBrake(EletropneumaticBrakeType.None, Train.Handles.EmergencyBrake, Train.Handles.Reverser, true, 0.0, 0.0, new AccelerationCurve[] {}); } //At the minute, Object Viewer uses dummy brake systems Train.Cars[i].CarBrake.mainReservoir = new MainReservoir((int)numericUpDownMain.Value * 1000); Train.Cars[i].CarBrake.brakePipe = new BrakePipe((int)numericUpDownPipe.Value * 1000); Train.Cars[i].CarBrake.brakeCylinder = new BrakeCylinder((int)numericUpDownCylinder.Value * 1000); Train.Cars[i].CarBrake.straightAirPipe = new StraightAirPipe((int)numericUpDownAirPipe.Value * 1000); Train.Cars[i].Doors[0] = new Door(-1, 1000, 0) { State = (double)numericUpDownLeft.Value, AnticipatedOpen = checkBoxLeftTarget.Checked }; Train.Cars[i].Doors[1] = new Door(1, 1000, 0) { State = (double)numericUpDownRight.Value, AnticipatedOpen = checkBoxRightTarget.Checked }; } Train.Handles.Reverser.Driver = (ReverserPosition)numericUpDownReverser.Value; Train.Handles.Reverser.Actual = (ReverserPosition)numericUpDownReverser.Value; if ((int)numericUpDownPowerNotches.Value != Train.Handles.Power.MaximumNotch) { Train.Handles.Power = new PowerHandle((int)numericUpDownPowerNotches.Value, (int)numericUpDownPowerNotches.Value, new double[] {}, new double[] {}, Train); } Train.Handles.Power.Driver = (int)numericUpDownPowerNotch.Value; if (checkBoxAirBrake.Checked) { Train.Handles.Brake.Driver = (int)numericUpDownBrakeNotch.Value; } else { if ((int)numericUpDownBrakeNotches.Value != Train.Handles.Brake.MaximumNotch) { Train.Handles.Brake = new BrakeHandle((int)numericUpDownBrakeNotches.Value, (int)numericUpDownBrakeNotches.Value, null, new double[] {}, new double[] {}, Train); } Train.Handles.Brake.Driver = (int)numericUpDownBrakeNotch.Value; Train.Handles.HasHoldBrake = checkBoxHoldBrake.Checked; if (checkBoxHoldBrake.Checked) { Train.Handles.HoldBrake.Driver = checkBoxSetHoldBrake.Checked; } } Train.Handles.EmergencyBrake.Driver = checkBoxSetEmergency.Checked; Train.Specs.HasConstSpeed = checkBoxConstSpeed.Checked; if (checkBoxConstSpeed.Checked) { Train.Specs.CurrentConstSpeed = checkBoxSetConstSpeed.Checked; } Train.SafetySystemPlugin = checkBoxEnablePlugin.Checked; if (checkBoxEnablePlugin.Checked && PluginStates.Count != 0) { PluginManager.CurrentPlugin.Panel = new int[PluginStates.Max(value => value.Number) + 1]; foreach (PluginState state in PluginStates) { PluginManager.CurrentPlugin.Panel[state.Number] = state.State; } } else { PluginManager.CurrentPlugin.Panel = new int[] { }; } Program.TrainManager.Trains[0] = Train; } } }
/// <summary>Loads the sound set for a BVE2 based train</summary> /// <param name="train">The train</param> /// <param name="trainFolder">The absolute on-disk path to the train's folder</param> internal static void Parse(string trainFolder, TrainManager.Train train) { // set sound positions and radii Vector3 front = new Vector3(0.0, 0.0, 0.5 * train.Cars[train.DriverCar].Length); Vector3 center = new Vector3(0.0, 0.0, 0.0); Vector3 left = new Vector3(-1.3, 0.0, 0.0); Vector3 right = new Vector3(1.3, 0.0, 0.0); Vector3 cab = new Vector3(-train.Cars[train.DriverCar].Driver.X, train.Cars[train.DriverCar].Driver.Y, train.Cars[train.DriverCar].Driver.Z - 0.5); Vector3 panel = new Vector3(train.Cars[train.DriverCar].Driver.X, train.Cars[train.DriverCar].Driver.Y, train.Cars[train.DriverCar].Driver.Z + 1.0); train.InitializeCarSounds(); // load sounds for driver's car train.Cars[train.DriverCar].Sounds.Adjust = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Adjust.wav"), panel, SoundCfgParser.tinyRadius); train.Cars[train.DriverCar].Sounds.Brake = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Brake.wav"), center, SoundCfgParser.smallRadius); train.Cars[train.DriverCar].Sounds.Halt = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Halt.wav"), cab, SoundCfgParser.tinyRadius); train.Cars[train.DriverCar].Sounds.Horns[0].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon0.wav"), SoundCfgParser.smallRadius); train.Cars[train.DriverCar].Sounds.Horns[0].Loop = false; train.Cars[train.DriverCar].Sounds.Horns[0].SoundPosition = front; if (train.Cars[train.DriverCar].Sounds.Horns[0].LoopSound == null) { train.Cars[train.DriverCar].Sounds.Horns[0].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon.wav"), SoundCfgParser.largeRadius); } train.Cars[train.DriverCar].Sounds.Horns[1].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon1.wav"), SoundCfgParser.largeRadius); train.Cars[train.DriverCar].Sounds.Horns[1].Loop = false; train.Cars[train.DriverCar].Sounds.Horns[1].SoundPosition = front; train.Cars[train.DriverCar].Sounds.Horns[2].LoopSound = Sounds.SoundBuffer.TryToLoad(OpenBveApi.Path.CombineFile(trainFolder, "Klaxon2.wav"), SoundCfgParser.mediumRadius); train.Cars[train.DriverCar].Sounds.Horns[2].Loop = true; train.Cars[train.DriverCar].Sounds.Horns[2].SoundPosition = front; train.Cars[train.DriverCar].Sounds.PilotLampOn = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Leave.wav"), cab, SoundCfgParser.tinyRadius); train.Cars[train.DriverCar].Sounds.PilotLampOff = TrainManager.CarSound.Empty; // load sounds for all cars for (int i = 0; i < train.Cars.Length; i++) { Vector3 frontaxle = new Vector3(0.0, 0.0, train.Cars[i].FrontAxle.Position); Vector3 rearaxle = new Vector3(0.0, 0.0, train.Cars[i].RearAxle.Position); train.Cars[i].Sounds.Air = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Air.wav"), center, SoundCfgParser.smallRadius); train.Cars[i].Sounds.AirHigh = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "AirHigh.wav"), center, SoundCfgParser.smallRadius); train.Cars[i].Sounds.AirZero = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "AirZero.wav"), center, SoundCfgParser.smallRadius); if (train.Cars[i].Specs.AirBrake.Type == TrainManager.AirBrakeType.Main) { train.Cars[i].Sounds.CpEnd = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "CpEnd.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.CpLoop = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "CpLoop.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.CpStart = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "CpStart.wav"), center, SoundCfgParser.mediumRadius); } train.Cars[i].Sounds.BreakerResume = TrainManager.CarSound.Empty; train.Cars[i].Sounds.BreakerResumeOrInterrupt = TrainManager.CarSound.Empty; train.Cars[i].Sounds.BreakerResumed = false; train.Cars[i].Sounds.DoorCloseL = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorClsL.wav"), left, SoundCfgParser.smallRadius); train.Cars[i].Sounds.DoorCloseR = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorClsR.wav"), right, SoundCfgParser.smallRadius); if (train.Cars[i].Sounds.DoorCloseL.Buffer == null) { train.Cars[i].Sounds.DoorCloseL = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorCls.wav"), left, SoundCfgParser.smallRadius); } if (train.Cars[i].Sounds.DoorCloseR.Buffer == null) { train.Cars[i].Sounds.DoorCloseR = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorCls.wav"), right, SoundCfgParser.smallRadius); } train.Cars[i].Sounds.DoorOpenL = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpnL.wav"), left, SoundCfgParser.smallRadius); train.Cars[i].Sounds.DoorOpenR = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpnR.wav"), right, SoundCfgParser.smallRadius); if (train.Cars[i].Sounds.DoorOpenL.Buffer == null) { train.Cars[i].Sounds.DoorOpenL = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpn.wav"), left, SoundCfgParser.smallRadius); } if (train.Cars[i].Sounds.DoorOpenR.Buffer == null) { train.Cars[i].Sounds.DoorOpenR = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "DoorOpn.wav"), right, SoundCfgParser.smallRadius); } train.Cars[i].Sounds.EmrBrake = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "EmrBrake.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.Flange = SoundCfgParser.TryLoadSoundArray(trainFolder, "Flange", ".wav", center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.FlangeVolume = new double[train.Cars[i].Sounds.Flange.Length]; train.Cars[i].Sounds.Loop = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Loop.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.PointFrontAxle = new TrainManager.CarSound[] { new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Point.wav"), frontaxle, SoundCfgParser.smallRadius) }; train.Cars[i].Sounds.PointRearAxle = new TrainManager.CarSound[] { new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Point.wav"), rearaxle, SoundCfgParser.smallRadius) }; train.Cars[i].Sounds.Rub = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Rub.wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.Run = SoundCfgParser.TryLoadSoundArray(trainFolder, "Run", ".wav", center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.RunVolume = new double[train.Cars[i].Sounds.Run.Length]; train.Cars[i].Sounds.SpringL = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "SpringL.wav"), left, SoundCfgParser.smallRadius); train.Cars[i].Sounds.SpringR = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "SpringR.wav"), right, SoundCfgParser.smallRadius); // motor sound if (train.Cars[i].Specs.IsMotorCar) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; train.Cars[i].Sounds.Motor.Position = center; for (int j = 0; j < train.Cars[i].Sounds.Motor.Tables.Length; j++) { for (int k = 0; k < train.Cars[i].Sounds.Motor.Tables[j].Entries.Length; k++) { int idx = train.Cars[i].Sounds.Motor.Tables[j].Entries[k].SoundIndex; if (idx >= 0) { TrainManager.CarSound snd = new TrainManager.CarSound(OpenBveApi.Path.CombineFile(trainFolder, "Motor" + idx.ToString(Culture) + ".wav"), center, SoundCfgParser.mediumRadius); train.Cars[i].Sounds.Motor.Tables[j].Entries[k].Buffer = snd.Buffer; } } } } } }
private formTrain() { InitializeComponent(); checkBoxEnableTrain.Checked = Program.TrainManager.Trains.Length != 0; tabControlSettings.Enabled = checkBoxEnableTrain.Checked; labelEmergency.Enabled = false; numericUpDownEmergency.Enabled = false; checkBoxSetHoldBrake.Enabled = false; checkBoxSetConstSpeed.Enabled = false; TrainManager.Train Train = Program.TrainManager.Trains[0] as TrainManager.Train; if (checkBoxEnableTrain.Checked) { numericUpDownCars.Value = Train.Cars.Length; numericUpDownSpeed.Value = (decimal)(Train.Cars[0].CurrentSpeed * 3.6); numericUpDownAccel.Value = (decimal)(Train.Cars[0].Specs.MotorAcceleration * 3.6); numericUpDownMain.Value = (decimal)(Train.Cars[0].CarBrake.mainReservoir.CurrentPressure / 1000.0); numericUpDownPipe.Value = (decimal)(Train.Cars[0].CarBrake.brakePipe.CurrentPressure / 1000.0); numericUpDownCylinder.Value = (decimal)(Train.Cars[0].CarBrake.brakeCylinder.CurrentPressure / 1000.0); numericUpDownAirPipe.Value = (decimal)(Train.Cars[0].CarBrake.straightAirPipe.CurrentPressure / 1000.0); numericUpDownLeft.Value = (decimal)Train.Cars[0].Doors[0].State; numericUpDownRight.Value = (decimal)Train.Cars[0].Doors[1].State; checkBoxLeftTarget.Checked = Train.Cars[0].Doors[0].AnticipatedOpen; checkBoxRightTarget.Checked = Train.Cars[0].Doors[1].AnticipatedOpen; numericUpDownReverser.Value = (decimal)Train.Handles.Reverser.Driver; numericUpDownPowerNotch.Value = Train.Handles.Power.Driver; numericUpDownPowerNotches.Value = Train.Handles.Power.MaximumNotch; checkBoxAirBrake.Checked = Train.Cars[0].CarBrake is AutomaticAirBrake; if (checkBoxAirBrake.Checked) { numericUpDownBrakeNotch.Value = (int)Train.Handles.Brake.Driver; numericUpDownBrakeNotch.Maximum = 2; numericUpDownBrakeNotches.Value = 2; numericUpDownBrakeNotches.Enabled = false; checkBoxHoldBrake.Enabled = false; } else { numericUpDownBrakeNotch.Value = Train.Handles.Brake.Driver; numericUpDownBrakeNotches.Value = Train.Handles.Brake.MaximumNotch; checkBoxHoldBrake.Checked = Train.Handles.HasHoldBrake; if (checkBoxHoldBrake.Checked) { checkBoxSetHoldBrake.Enabled = true; checkBoxSetHoldBrake.Checked = Train.Handles.HoldBrake.Driver; } } checkBoxSetEmergency.Checked = Train.Handles.EmergencyBrake.Driver; checkBoxConstSpeed.Checked = Train.Specs.HasConstSpeed; if (checkBoxConstSpeed.Checked) { checkBoxSetConstSpeed.Enabled = true; checkBoxSetConstSpeed.Checked = Train.Specs.CurrentConstSpeed; } checkBoxEnablePlugin.Checked = Train.SafetySystemPlugin; } panelPlugin.Enabled = checkBoxEnablePlugin.Checked; buttonRemove.Enabled = false; labelNumber.Enabled = false; numericUpDownNumber.Enabled = false; labelState.Enabled = false; numericUpDownState.Enabled = false; PluginStates = new List <PluginState>(); for (int i = 0; i < PluginManager.CurrentPlugin.Panel.Length; i++) { if (PluginManager.CurrentPlugin.Panel[i] != 0) { PluginStates.Add(new PluginState(i, PluginManager.CurrentPlugin.Panel[i])); } } ListPluginStates(); }
internal static void Parse(string fileName, ref TrainManager.Train Train, ref TrainManager.Car car, bool isDriverCar) { //3D center of the car Vector3 center = Vector3.Zero; //Positioned to the left of the car, but centered Y & Z Vector3 left = new Vector3(-1.3, 0.0, 0.0); //Positioned to the right of the car, but centered Y & Z Vector3 right = new Vector3(1.3, 0.0, 0.0); //Positioned at the front of the car, centered X and Y Vector3 front = new Vector3(0.0, 0.0, 0.5 * car.Length); //Positioned at the position of the panel / 3D cab (Remember that the panel is just an object in the world...) Vector3 panel = new Vector3(car.Driver.X, car.Driver.Y, car.Driver.Z + 1.0); //The current XML file to load XmlDocument currentXML = new XmlDocument(); //Load the marker's XML file currentXML.Load(fileName); currentPath = System.IO.Path.GetDirectoryName(fileName); if (currentXML.DocumentElement != null) { XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/CarSounds"); if (DocumentNodes == null || DocumentNodes.Count == 0) { Interface.AddMessage(MessageType.Error, false, "No car sound nodes defined in XML file " + fileName); //If we have no appropriate nodes specified, return false and fallback to loading the legacy Sound.cfg file throw new Exception("Empty sound.xml file"); } foreach (XmlNode n in DocumentNodes) { if (n.ChildNodes.OfType <XmlElement>().Any()) { foreach (XmlNode c in n.ChildNodes) { switch (c.Name.ToLowerInvariant()) { case "ats": case "plugin": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of plugin sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } ParseArrayNode(c, out car.Sounds.Plugin, center, SoundCfgParser.mediumRadius); break; case "brake": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of brake sounds was defined in in XML file " + fileName); break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "releasehigh": //Release brakes from high pressure ParseNode(cc, out car.CarBrake.AirHigh, center, SoundCfgParser.smallRadius); break; case "release": //Release brakes from normal pressure ParseNode(cc, out car.CarBrake.Air, center, SoundCfgParser.smallRadius); break; case "releasefull": //Release brakes from full pressure ParseNode(cc, out car.CarBrake.AirZero, center, SoundCfgParser.smallRadius); break; case "emergency": //Apply EB ParseNode(cc, out Train.Handles.EmergencyBrake.ApplicationSound, center, SoundCfgParser.smallRadius); break; case "emergencyrelease": //Release EB ParseNode(cc, out Train.Handles.EmergencyBrake.ReleaseSound, center, SoundCfgParser.smallRadius); break; case "application": //Standard application ParseNode(cc, out car.Sounds.Brake, center, SoundCfgParser.smallRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "brakehandle": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of brake handle sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "apply": ParseNode(cc, out Train.Handles.Brake.Increase, panel, SoundCfgParser.tinyRadius); break; case "applyfast": ParseNode(cc, out Train.Handles.Brake.IncreaseFast, panel, SoundCfgParser.tinyRadius); break; case "release": ParseNode(cc, out Train.Handles.Brake.Decrease, panel, SoundCfgParser.tinyRadius); break; case "releasefast": ParseNode(cc, out Train.Handles.Brake.DecreaseFast, panel, SoundCfgParser.tinyRadius); break; case "min": case "minimum": ParseNode(cc, out Train.Handles.Brake.Min, panel, SoundCfgParser.tinyRadius); break; case "max": case "maximum": ParseNode(cc, out Train.Handles.Brake.Max, panel, SoundCfgParser.tinyRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "breaker": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of breaker sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "on": ParseNode(cc, out car.Sounds.BreakerResume, panel, SoundCfgParser.smallRadius); break; case "off": ParseNode(cc, out car.Sounds.BreakerResumeOrInterrupt, panel, SoundCfgParser.smallRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "buzzer": if (!isDriverCar) { break; } ParseNode(c, out Train.SafetySystems.StationAdjust.AdjustAlarm, panel, SoundCfgParser.tinyRadius); break; case "compressor": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of compressor sounds was defined in in XML file " + fileName); break; } if (car.CarBrake.brakeType != BrakeType.Main) { break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "attack": case "start": //Compressor starting sound ParseNode(cc, out car.CarBrake.airCompressor.StartSound, center, SoundCfgParser.mediumRadius); break; case "loop": //Compressor loop sound ParseNode(cc, out car.CarBrake.airCompressor.LoopSound, center, SoundCfgParser.mediumRadius); break; case "release": case "stop": case "end": //Compressor end sound ParseNode(cc, out car.CarBrake.airCompressor.EndSound, center, SoundCfgParser.mediumRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "door": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of door sounds was defined in in XML file " + fileName); break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "openleft": case "leftopen": ParseNode(cc, out car.Doors[0].OpenSound, left, SoundCfgParser.smallRadius); break; case "openright": case "rightopen": ParseNode(cc, out car.Doors[1].OpenSound, right, SoundCfgParser.smallRadius); break; case "closeleft": case "leftclose": ParseNode(cc, out car.Doors[0].CloseSound, left, SoundCfgParser.smallRadius); break; case "closeright": case "rightclose": ParseNode(cc, out car.Doors[1].CloseSound, right, SoundCfgParser.smallRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "flange": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of flange sounds was defined in in XML file " + fileName); break; } ParseArrayNode(c, out car.Sounds.Flange, center, SoundCfgParser.mediumRadius); break; case "horn": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of horn sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "primary": //Primary horn ParseHornNode(cc, out car.Horns[0], front, SoundCfgParser.largeRadius); break; case "secondary": //Secondary horn ParseHornNode(cc, out car.Horns[1], front, SoundCfgParser.largeRadius); break; case "music": //Music horn ParseHornNode(cc, out car.Horns[2], front, SoundCfgParser.largeRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "loop": case "noise": ParseNode(c, out car.Sounds.Loop, center, SoundCfgParser.mediumRadius); break; case "mastercontroller": case "powerhandle": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of power handle sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "up": case "increase": ParseNode(cc, out Train.Handles.Power.Increase, panel, SoundCfgParser.tinyRadius); break; case "upfast": case "increasefast": ParseNode(cc, out Train.Handles.Power.IncreaseFast, panel, SoundCfgParser.tinyRadius); break; case "down": case "decrease": ParseNode(cc, out Train.Handles.Power.Decrease, panel, SoundCfgParser.tinyRadius); break; case "downfast": case "decreasefast": ParseNode(cc, out Train.Handles.Power.DecreaseFast, panel, SoundCfgParser.tinyRadius); break; case "min": case "minimum": ParseNode(cc, out Train.Handles.Power.Min, panel, SoundCfgParser.tinyRadius); break; case "max": case "maximum": ParseNode(cc, out Train.Handles.Power.Max, panel, SoundCfgParser.tinyRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "motor": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, string.Format("An empty list of motor sounds was defined in in XML file {0}", fileName)); break; } if (!car.Specs.IsMotorCar) { break; } ParseMotorSoundTableNode(c, ref car.Sounds.Motor.Tables, center, SoundCfgParser.mediumRadius); break; case "pilotlamp": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of pilot-lamp sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "on": ParseNode(cc, out Train.SafetySystems.PilotLamp.OnSound, panel, SoundCfgParser.tinyRadius); break; case "off": ParseNode(cc, out Train.SafetySystems.PilotLamp.OffSound, panel, SoundCfgParser.tinyRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "pointfrontaxle": case "switchfrontaxle": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of point front axle sounds was defined in in XML file " + fileName); break; } CarSound[] frontAxlePointSounds; ParseArrayNode(c, out frontAxlePointSounds, new Vector3(0.0, 0.0, car.FrontAxle.Position), SoundCfgParser.smallRadius); car.FrontAxle.PointSounds = frontAxlePointSounds; break; case "pointrearaxle": case "switchrearaxle": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of point rear axle sounds was defined in in XML file " + fileName); break; } CarSound[] rearAxlePointSounds; ParseArrayNode(c, out rearAxlePointSounds, new Vector3(0.0, 0.0, car.FrontAxle.Position), SoundCfgParser.smallRadius); car.RearAxle.PointSounds = rearAxlePointSounds; break; case "reverser": case "reverserhandle": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of reverser sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "on": ParseNode(cc, out Train.Handles.Reverser.EngageSound, panel, SoundCfgParser.tinyRadius); break; case "off": ParseNode(cc, out Train.Handles.Reverser.ReleaseSound, panel, SoundCfgParser.tinyRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "run": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of run sounds was defined in in XML file " + fileName); break; } ParseArrayNode(c, out car.Sounds.Run, center, SoundCfgParser.mediumRadius); break; case "shoe": case "rub": ParseNode(c, out car.CarBrake.Rub, center, SoundCfgParser.mediumRadius); break; case "suspension": case "spring": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of suspension sounds was defined in in XML file " + fileName); break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "left": //Left suspension springs ParseNode(cc, out car.Sounds.SpringL, left, SoundCfgParser.smallRadius); break; case "right": //right suspension springs ParseNode(cc, out car.Sounds.SpringR, right, SoundCfgParser.smallRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "requeststop": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of request stop sounds was defined in in XML file " + fileName); break; } foreach (XmlNode cc in c.ChildNodes) { switch (cc.Name.ToLowerInvariant()) { case "stop": ParseNode(cc, out car.Sounds.RequestStop[0], center, SoundCfgParser.smallRadius); break; case "pass": ParseNode(cc, out car.Sounds.RequestStop[1], center, SoundCfgParser.smallRadius); break; case "ignored": ParseNode(cc, out car.Sounds.RequestStop[2], center, SoundCfgParser.smallRadius); break; default: Interface.AddMessage(MessageType.Error, false, "Declaration " + cc.Name + " is unsupported in a " + c.Name + " node."); break; } } break; case "touch": if (!c.ChildNodes.OfType <XmlElement>().Any()) { Interface.AddMessage(MessageType.Error, false, "An empty list of touch sounds was defined in in XML file " + fileName); break; } if (!isDriverCar) { break; } ParseArrayNode(c, out car.Sounds.Touch, center, SoundCfgParser.mediumRadius); break; } } } } car.Sounds.RunVolume = new double[car.Sounds.Run.Length]; car.Sounds.FlangeVolume = new double[car.Sounds.Flange.Length]; } }
internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (Train == TrainManager.PlayerTrain & TriggerType == EventTriggerType.FrontCarFrontAxle) { if (this.Message != null) { if (Direction < 0) { if (this.Message.Trains != null && !this.Message.Trains.Contains(new System.IO.DirectoryInfo(Game.RouteInformation.TrainFolder).Name)) { //Our train is NOT in the list of trains which this message triggers for return; } MessageManager.AddMessage(this.Message); } else if (Direction > 0) { this.Message.QueueForRemoval = true; } } } }