Пример #1
0
 /// <summary>This method returns the current aspect of the selected section</summary>
 /// <param name="Train">The train for which we wish to get the section index</param>
 /// <param name="SectionIndex">The section to get the aspect for</param>
 /// <param name="IsPartOfTrain">Defines whether we wish to get the section index for the selected train, or for when placed via a .SigF command</param>
 /// <returns>The aspect of the selected signal</returns>
 public static int CurrentAspect(TrainManager.Train Train, int SectionIndex, bool IsPartOfTrain)
 {
     if (IsPartOfTrain)
     {
         int nextSectionIndex = Train.CurrentSectionIndex + 1;
         if (nextSectionIndex >= 0 & nextSectionIndex < Game.Sections.Length)
         {
             int a = Game.Sections[nextSectionIndex].CurrentAspect;
             if (a >= 0 & a < Game.Sections[nextSectionIndex].Aspects.Length)
             {
                 return Game.Sections[nextSectionIndex].Aspects[a].Number;
             }
             return 0;
         }
     }
     else if (SectionIndex >= 0 & SectionIndex < Game.Sections.Length)
     {
         int a = Game.Sections[SectionIndex].CurrentAspect;
         if (a >= 0 & a < Game.Sections[SectionIndex].Aspects.Length)
         {
             return Game.Sections[SectionIndex].Aspects[a].Number;
         }
     }
     return 0;
 }
Пример #2
0
 /// <summary>Unloads the currently loaded plugin, if any.</summary>
 /// <param name="train">Unloads the plugin for the specified train.</param>
 internal static void UnloadPlugin(TrainManager.Train train)
 {
     if (train.Plugin != null) {
         train.Plugin.Unload();
         train.Plugin = null;
     }
 }
Пример #3
0
 /// <summary>
 /// close left door
 /// </summary>
 static public void RightDoorClose()
 {
     try
     {
         TrainManager.CloseTrainDoors(TrainManager.PlayerTrain, false, true);
     }
     catch (Exception ex) { }
 }
Пример #4
0
 /// <summary>
 /// open left door
 /// </summary>
 static public void LeftDoorOpen()
 {
     try
     {
         TrainManager.OpenTrainDoors(TrainManager.PlayerTrain, true, false);
     }
     catch (Exception ex) { }
 }
Пример #5
0
 /// <summary>Returns the number of cars in this train</summary>
 /// <param name="Train">The selected train</param>
 /// <returns>The number of cars</returns>
 public static int numberOfCars(TrainManager.Train Train)
 {
     if (Train != null)
     {
         return Train.Cars.Length;
     }
     return 0;
 }
Пример #6
0
 static public void SetLeftDoorClose()
 {
     try
     {
         TrainManager.CloseTrainDoors(TrainManager.PlayerTrain, true, false);
     }
     catch (Exception) { };
 }
Пример #7
0
 static public void SetRightDoorOpen()
 {
     try
     {
         TrainManager.OpenTrainDoors(TrainManager.PlayerTrain, false, true);
     }
     catch (Exception) { };
 }
Пример #8
0
		// parse sound config
		internal static void ParseSoundConfig(string TrainPath, System.Text.Encoding Encoding, TrainManager.Train Train) {
			string FileName = OpenBveApi.Path.CombineFile(TrainPath, "sound.cfg");
			if (System.IO.File.Exists(FileName)) {
				LoadBve4Sound(FileName, TrainPath, Encoding, Train);
			} else {
				LoadBve2Sound(TrainPath, Train);
			}
		}
Пример #9
0
 /// <summary>
 /// set reverser
 /// </summary>
 static public void SetReverser(int value)
 {
     try
     {
         TrainManager.ApplyReverser(nowControl, value, false);
         return;
     }
     catch (Exception ex) { }
 }
Пример #10
0
			internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) {
				if (TriggerType == EventTriggerType.Camera) {
					if (Direction < 0) {
						BackgroundManager.TargetBackground = this.PreviousBackground;
					} else if (Direction > 0) {
						BackgroundManager.TargetBackground = this.NextBackground;
					}
				}
			}
Пример #11
0
 /// <summary>Loads the default plugin for the specified train.</summary>
 /// <param name="train">The train to attach the plugin to.</param>
 /// <param name="trainFolder">The train folder.</param>
 /// <returns>Whether the plugin was loaded successfully.</returns>
 internal static bool LoadDefaultPlugin(TrainManager.Train train, string trainFolder)
 {
     string file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Plugins"), "OpenBveAts.dll");
     bool success = LoadPlugin(train, file, trainFolder);
     if (success) {
         train.Plugin.IsDefault = true;
         SoundCfgParser.LoadDefaultPluginSounds(train, trainFolder);
     }
     return success;
 }
Пример #12
0
 /// <summary>
 /// reserver backward
 /// </summary>
 static public void ReverserBackward()
 {
     try
     {
         TrainManager.ApplyReverser(nowControl, -1, true);
         TrainManager.ApplyReverser(nowControl, -1, true);
         return;
     }
     catch (Exception ex) { }
 }
Пример #13
0
 override internal void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) {
     if (TriggerType == EventTriggerType.Camera) {
         if (Direction < 0) {
             World.TargetBackground = this.PreviousBackground;
             World.TargetBackgroundCountdown = World.TargetBackgroundDefaultCountdown;
         } else if (Direction > 0) {
             World.TargetBackground = this.NextBackground;
             World.TargetBackgroundCountdown = World.TargetBackgroundDefaultCountdown;
         }
     }
 }
Пример #14
0
			internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) {
				if (TriggerType == EventTriggerType.Camera) {
					if (Direction < 0) {
						Game.PreviousFog = this.PreviousFog;
						Game.NextFog = this.CurrentFog;
					} else if (Direction > 0) {
						Game.PreviousFog = this.CurrentFog;
						Game.NextFog = this.NextFog;
					}
				}
			}
Пример #15
0
 /// <summary>Returns the speed of the selected car </summary>
 /// <param name="Train">The selected train</param>
 /// <param name="CarIndex">The car for which to get the speed</param>
 /// <returns>The speed in m/s</returns>
 public static double speed(TrainManager.Train Train, int CarIndex)
 {
     if (Train == null)
     {
         return 0;
     }
     if (CarIndex > Train.Cars.Length)
     {
         return Train.Cars[0].Specs.CurrentSpeed;
     }
     return Train.Cars[CarIndex].Specs.CurrentSpeed;
 }
Пример #16
0
		internal static void LoadDefaultPluginSounds(TrainManager.Train train, string trainFolder) {
			Vector3D position = new Vector3D(train.Cars[train.DriverCar].DriverX, train.Cars[train.DriverCar].DriverY, train.Cars[train.DriverCar].DriverZ + 1.0);
			const double radius = 2.0;
			train.Cars[train.DriverCar].Sounds.Plugin = new TrainManager.CarSound[] {
				TryLoadSound(OpenBveApi.Path.CombineFile(trainFolder, "ats.wav"), position, radius),
				TryLoadSound(OpenBveApi.Path.CombineFile(trainFolder, "atscnt.wav"), position, radius),
				TryLoadSound(OpenBveApi.Path.CombineFile(trainFolder, "ding.wav"), position, radius),
				TryLoadSound(OpenBveApi.Path.CombineFile(trainFolder, "toats.wav"), position, radius),
				TryLoadSound(OpenBveApi.Path.CombineFile(trainFolder, "toatc.wav"), position, radius),
				TryLoadSound(OpenBveApi.Path.CombineFile(trainFolder, "eb.wav"), position, radius)
			};
		}
Пример #17
0
			// --- 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;
			}
Пример #18
0
			internal double Perform(TrainManager.Train Train, int CarIndex, Vector3 Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed, int CurrentState) {
				ExecuteFunctionScript(this, Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState);

				//Allows us to pin the result, but keep the underlying figure
				if (this.Minimum != Double.NaN & this.LastResult < Minimum)
				{
					return Minimum;
				}
				if (this.Maximum != Double.NaN & this.LastResult > Maximum)
				{
					return Maximum;
				}
				return this.LastResult;
			}
Пример #19
0
 // load no sound
 internal static void LoadNoSound(TrainManager.Train train)
 {
     // initialize
     for (int i = 0; i < train.Cars.Length; i++) {
         train.Cars[i].Sounds.Run = new TrainManager.CarSound[] { };
         train.Cars[i].Sounds.Flange = new TrainManager.CarSound[] { };
         train.Cars[i].Sounds.Adjust = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.Air = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.AirHigh = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.AirZero = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.Brake = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.BrakeHandleApply = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.BrakeHandleMin = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.BrakeHandleMax = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.BrakeHandleRelease = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.BreakerResume = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.BreakerResumeOrInterrupt = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.CpEnd = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.CpLoop = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.CpStart = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.DoorCloseL = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.DoorCloseR = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.DoorOpenL = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.DoorOpenR = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.EmrBrake = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.Flange = new TrainManager.CarSound[] { };
         train.Cars[i].Sounds.FlangeVolume = new double[] { };
         train.Cars[i].Sounds.Halt = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.Horns = new TrainManager.Horn[] { TrainManager.Horn.Empty, TrainManager.Horn.Empty, TrainManager.Horn.Empty };
         train.Cars[i].Sounds.Loop = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.MasterControllerUp = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.MasterControllerDown = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.MasterControllerMin = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.MasterControllerMax = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.PilotLampOn = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.PilotLampOff = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.PointFrontAxle = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.PointRearAxle = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.ReverserOn = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.ReverserOff = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.Rub = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.Run = new TrainManager.CarSound[] { };
         train.Cars[i].Sounds.RunVolume = new double[] { };
         train.Cars[i].Sounds.SpringL = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.SpringR = TrainManager.CarSound.Empty;
         train.Cars[i].Sounds.Plugin = new TrainManager.CarSound[] { };
     }
 }
Пример #20
0
        /// <summary>
        /// main timer interrupt
        /// </summary>
        static private void MainTimerProcess(object state)
        {
            if (Interlocked.Exchange(ref inTimer_Main, 1) == 0)
            {
                try
                {
                    nowControl = TrainManager.PlayerTrain;
                    //Master key
                    if (!MasterKey)
                    {
                        SetAutoPilot(0);
                        SetBrake(0);
                        SetPower(0);
                        ReverserNeutral();
                    }

                    //emergency
                    if (Emergency)
                    {
                        SetAutoPilot(0);
                        TrainManager.ApplyEmergencyBrake(nowControl);
                    }
                    else
                    {
                        TrainManager.UnapplyEmergencyBrake(nowControl);
                    }

                    //signal
                    if (GetSignal() == 0)
                    {
                        inRedLight = true;
                    }
                    else
                    {
                        if (inRedLight)
                        {
                            SetBrake(nowControl.Handles.Brake.MaximumNotch);
                            SetReverser(0);
                            SetAutoPilot(0);
                        }
                        inRedLight = false;
                    }
                }
                catch (Exception ex) { }
                Interlocked.Exchange(ref inTimer_Main, 0);
            }
        }
Пример #21
0
 private OpenBveApi.Runtime.AIResponse PerformPlugin(TrainManager.Train Train)
 {
     OpenBveApi.Runtime.AIResponse response = Train.Plugin.UpdateAI();
     if (response == OpenBveApi.Runtime.AIResponse.Short)
     {
         CurrentInterval = 0.2 + 0.1 * Program.RandomNumberGenerator.NextDouble();
     }
     else if (response == OpenBveApi.Runtime.AIResponse.Medium)
     {
         CurrentInterval = 0.4 + 0.2 * Program.RandomNumberGenerator.NextDouble();
     }
     else if (response == OpenBveApi.Runtime.AIResponse.Long)
     {
         CurrentInterval = 0.8 + 0.4 * Program.RandomNumberGenerator.NextDouble();
     }
     return response;
 }
Пример #22
0
 /// <summary>
 /// set emergency
 /// </summary>
 static public void SetEmergency(int value)
 {
     try
     {
         Emergency = value == 0 ? false : true;
         TrainManager.Train nowControl = TrainManager.PlayerTrain;
         if (Emergency)
         {
             TrainManager.ApplyEmergencyBrake(nowControl);
         }
         else
         {
             TrainManager.UnapplyEmergencyBrake(nowControl);
         }
     }
     catch (Exception ex) { }
 }
Пример #23
0
 // functions
 internal SimpleHumanDriverAI(TrainManager.Train Train)
 {
     this.TimeLastProcessed = 0.0;
     this.CurrentInterval = 1.0;
     this.BrakeMode = false;
     this.PersonalitySpeedFactor = 0.90 + 0.10 * Program.RandomNumberGenerator.NextDouble();
     this.CurrentSpeedFactor = this.PersonalitySpeedFactor;
     this.PowerNotchAtWhichWheelSlipIsObserved = Train.Specs.MaximumPowerNotch + 1;
     if (Train.Station >= 0 & Train.StationState == TrainManager.TrainStopState.Boarding)
     {
         this.LastStation = Train.Station;
     }
     else
     {
         this.LastStation = -1;
     }
 }
Пример #24
0
 /// <summary>Loads a custom plugin for the specified train.</summary>
 /// <param name="train">The train to attach the plugin to.</param>
 /// <param name="trainFolder">The absolute path to the train folder.</param>
 /// <param name="encoding">The encoding to be used.</param>
 /// <returns>Whether the plugin was loaded successfully.</returns>
 internal static bool LoadCustomPlugin(TrainManager.Train train, string trainFolder, System.Text.Encoding encoding)
 {
     string config = OpenBveApi.Path.CombineFile(trainFolder, "ats.cfg");
     if (!System.IO.File.Exists(config)) {
         return false;
     }
     string[] lines = System.IO.File.ReadAllLines(config, encoding);
     if (lines.Length == 0) {
         return false;
     }
     string file = OpenBveApi.Path.CombineFile(trainFolder, lines[0]);
     string title = System.IO.Path.GetFileName(file);
     if (!System.IO.File.Exists(file)) {
         Interface.AddMessage(Interface.MessageType.Error, true, "The train plugin " + title + " could not be found in " + config);
         return false;
     }
     return LoadPlugin(train, file, trainFolder);
 }
Пример #25
0
 /// <summary>
 /// get left door state
 /// </summary>
 static public int GetRightDoorState()
 {
     try
     {
         TrainManager.TrainDoorState value;
         value = TrainManager.GetDoorsState(TrainManager.PlayerTrain, false, true);
         if (value == TrainManager.TrainDoorState.AllClosed)
         {
             return(0);
         }
         if (value == TrainManager.TrainDoorState.AllOpened)
         {
             return(1);
         }
         return(-1);
     }
     catch (Exception ex) { }
     return(-1);
 }
Пример #26
0
		// --- constructors ---
		internal NetPlugin(string pluginFile, string trainFolder, IRuntime api, TrainManager.Train train) {
			base.PluginTitle = System.IO.Path.GetFileName(pluginFile);
			base.PluginValid = true;
			base.PluginMessage = null;
			base.Train = train;
			base.Panel = null;
			base.SupportsAI = false;
			base.LastTime = 0.0;
			base.LastReverser = -2;
			base.LastPowerNotch = -1;
			base.LastBrakeNotch = -1;
			base.LastAspects = new int[] { };
			base.LastSection = -1;
			base.LastException = null;
			this.PluginFolder = System.IO.Path.GetDirectoryName(pluginFile);
			this.TrainFolder = trainFolder;
			this.Api = api;
			this.SoundHandles = new SoundHandleEx[16];
			this.SoundHandlesCount = 0;
		}
Пример #27
0
 // --- constructors ---
 internal Win32Plugin(string pluginFile, TrainManager.Train train)
 {
     base.PluginTitle = System.IO.Path.GetFileName(pluginFile);
     base.PluginValid = true;
     base.PluginMessage = null;
     base.Train = train;
     base.Panel = new int[256];
     base.SupportsAI = false;
     base.LastTime = 0.0;
     base.LastReverser = -2;
     base.LastPowerNotch = -1;
     base.LastBrakeNotch = -1;
     base.LastAspects = new int[] { };
     base.LastSection = -1;
     base.LastException = null;
     this.PluginFile = pluginFile;
     this.Sound = new int[256];
     this.LastSound = new int[256];
     this.PanelHandle = new GCHandle();
     this.SoundHandle = new GCHandle();
 }
Пример #28
0
 /// <summary>
 /// power up
 /// </summary>
 static public void PowerUp()
 {
     try
     {
         int currretPower = nowControl.Handles.Power.Driver;
         int currentBrake = nowControl.Handles.Brake.Driver;
         if (nowControl.Handles.EmergencyBrake.Actual)
         {
             TrainManager.UnapplyEmergencyBrake(nowControl);
         }
         if (currentBrake > 0)
         {
             nowControl.ApplyNotch(0, true, -1, true);
         }
         else
         {
             nowControl.ApplyNotch(1, true, 0, true);
         }
         return;
     }
     catch (Exception ex) { }
 }
Пример #29
0
        static public int GetRightDoorState()
        {
            int retValue = -1;

            try
            {
                TrainManager.TrainDoorState dataValue;
                dataValue = TrainManager.GetDoorsState(TrainManager.PlayerTrain, false, true);
                if (dataValue == TrainManager.TrainDoorState.AllClosed)
                {
                    retValue = 0;
                }
                else if (dataValue == TrainManager.TrainDoorState.AllOpened)
                {
                    retValue = 1;
                }

                return(retValue);
            }
            catch (Exception) { };
            return(retValue);
        }
Пример #30
0
        /// <summary>This method is called once the route and train data have been preprocessed, in order to physically setup the simulation</summary>
        private void SetupSimulation()
        {
            if (Loading.Cancel)
            {
                Close();
            }
            Timetable.CreateTimetable();
            //Check if any critical errors have occured during the route or train loading
            for (int i = 0; i < Interface.MessageCount; i++)
            {
                if (Interface.Messages[i].Type == Interface.MessageType.Critical)
                {
                    MessageBox.Show("A critical error has occured:\n\n" + Interface.Messages[i].Text + "\n\nPlease inspect the error log file for further information.", "Load", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    Close();
                }
            }
            Renderer.InitializeLighting();
            Game.LogRouteName = System.IO.Path.GetFileName(MainLoop.currentResult.RouteFile);
            Game.LogTrainName = System.IO.Path.GetFileName(MainLoop.currentResult.TrainFolder);
            Game.LogDateTime  = DateTime.Now;

            if (Interface.CurrentOptions.LoadInAdvance)
            {
                Textures.LoadAllTextures();
            }
            else
            {
                Textures.UnloadAllTextures();
            }
            // camera
            ObjectManager.InitializeVisibility();
            World.CameraTrackFollower.Update(0.0, true, false);
            World.CameraTrackFollower.Update(-0.1, true, false);
            World.CameraTrackFollower.Update(0.1, true, false);
            World.CameraTrackFollower.TriggerType = TrackManager.EventTriggerType.Camera;
            // starting time and track position
            Game.SecondsSinceMidnight = 0.0;
            Game.StartupTime          = 0.0;
            int    PlayerFirstStationIndex = -1;
            double PlayerFirstStationPosition;
            int    os = -1;
            bool   f  = false;

            for (int i = 0; i < Game.Stations.Length; i++)
            {
                if (!String.IsNullOrEmpty(Game.InitialStationName))
                {
                    if (Game.InitialStationName.ToLowerInvariant() == Game.Stations[i].Name.ToLowerInvariant())
                    {
                        PlayerFirstStationIndex = i;
                    }
                }
                if (Game.Stations[i].StopMode == StationStopMode.AllStop | Game.Stations[i].StopMode == StationStopMode.PlayerStop & Game.Stations[i].Stops.Length != 0)
                {
                    if (f == false)
                    {
                        os = i;
                        f  = true;
                    }
                }
            }
            if (PlayerFirstStationIndex == -1)
            {
                PlayerFirstStationIndex = os;
            }
            {
                int s = Game.GetStopIndex(PlayerFirstStationIndex, TrainManager.PlayerTrain.Cars.Length);
                if (s >= 0)
                {
                    PlayerFirstStationPosition = Game.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition;

                    double TrainLength = 0.0;
                    for (int c = 0; c < TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars.Length; c++)
                    {
                        TrainLength += TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars[c].Length;
                    }

                    for (int j = 0; j < Game.BufferTrackPositions.Length; j++)
                    {
                        if (PlayerFirstStationPosition > Game.BufferTrackPositions[j] && PlayerFirstStationPosition - TrainLength < Game.BufferTrackPositions[j])
                        {
                            /*
                             * HACK: The initial start position for the player train is stuck on a set of buffers
                             * This means we have to make some one the fly adjustments to the first station stop position
                             */

                            //Set the start position to be the buffer position plus the train length plus 1m
                            PlayerFirstStationPosition = Game.BufferTrackPositions[j] + TrainLength + 1;
                            //Update the station stop location
                            if (s >= 0)
                            {
                                Game.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition = PlayerFirstStationPosition;
                            }
                            else
                            {
                                Game.Stations[PlayerFirstStationIndex].DefaultTrackPosition = PlayerFirstStationPosition;
                            }
                            break;
                        }
                    }
                }
                else
                {
                    PlayerFirstStationPosition = Game.Stations[PlayerFirstStationIndex].DefaultTrackPosition;
                }
                if (Game.InitialStationTime != -1)
                {
                    Game.SecondsSinceMidnight = Game.InitialStationTime;
                    Game.StartupTime          = Game.InitialStationTime;
                }
                else
                {
                    if (Game.Stations[PlayerFirstStationIndex].ArrivalTime < 0.0)
                    {
                        if (Game.Stations[PlayerFirstStationIndex].DepartureTime < 0.0)
                        {
                            Game.SecondsSinceMidnight = 0.0;
                            Game.StartupTime          = 0.0;
                        }
                        else
                        {
                            Game.SecondsSinceMidnight = Game.Stations[PlayerFirstStationIndex].DepartureTime -
                                                        Game.Stations[PlayerFirstStationIndex].StopTime;
                            Game.StartupTime = Game.Stations[PlayerFirstStationIndex].DepartureTime -
                                               Game.Stations[PlayerFirstStationIndex].StopTime;
                        }
                    }
                    else
                    {
                        Game.SecondsSinceMidnight = Game.Stations[PlayerFirstStationIndex].ArrivalTime;
                        Game.StartupTime          = Game.Stations[PlayerFirstStationIndex].ArrivalTime;
                    }
                }
            }
            int    OtherFirstStationIndex    = -1;
            double OtherFirstStationPosition = 0.0;
            double OtherFirstStationTime     = 0.0;

            for (int i = 0; i < Game.Stations.Length; i++)
            {
                if (Game.Stations[i].StopMode == StationStopMode.AllStop | Game.Stations[i].StopMode == StationStopMode.PlayerPass & Game.Stations[i].Stops.Length != 0)
                {
                    OtherFirstStationIndex = i;
                    int s = Game.GetStopIndex(i, TrainManager.PlayerTrain.Cars.Length);
                    if (s >= 0)
                    {
                        OtherFirstStationPosition = Game.Stations[i].Stops[s].TrackPosition;
                    }
                    else
                    {
                        OtherFirstStationPosition = Game.Stations[i].DefaultTrackPosition;
                    }
                    if (Game.Stations[i].ArrivalTime < 0.0)
                    {
                        if (Game.Stations[i].DepartureTime < 0.0)
                        {
                            OtherFirstStationTime = 0.0;
                        }
                        else
                        {
                            OtherFirstStationTime = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime;
                        }
                    }
                    else
                    {
                        OtherFirstStationTime = Game.Stations[i].ArrivalTime;
                    }
                    break;
                }
            }
            if (Game.PrecedingTrainTimeDeltas.Length != 0)
            {
                OtherFirstStationTime -= Game.PrecedingTrainTimeDeltas[Game.PrecedingTrainTimeDeltas.Length - 1];
                if (OtherFirstStationTime < Game.SecondsSinceMidnight)
                {
                    Game.SecondsSinceMidnight = OtherFirstStationTime;
                }
            }
            // initialize trains
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                TrainManager.Trains[i].Initialize();
                int s = i == TrainManager.PlayerTrain.TrainIndex ? PlayerFirstStationIndex : OtherFirstStationIndex;
                if (s >= 0)
                {
                    if (Game.Stations[s].OpenLeftDoors)
                    {
                        for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                        {
                            TrainManager.Trains[i].Cars[j].Doors[0].AnticipatedOpen = true;
                        }
                    }
                    if (Game.Stations[s].OpenRightDoors)
                    {
                        for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                        {
                            TrainManager.Trains[i].Cars[j].Doors[1].AnticipatedOpen = true;
                        }
                    }
                }
                if (Game.Sections.Length != 0)
                {
                    Game.Sections[0].Enter(TrainManager.Trains[i]);
                }
                for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                {
                    double length = TrainManager.Trains[i].Cars[0].Length;
                    TrainManager.Trains[i].Cars[j].Move(-length, 0.01);
                    TrainManager.Trains[i].Cars[j].Move(length, 0.01);
                }
            }
            // score
            Game.CurrentScore.ArrivalStation   = PlayerFirstStationIndex + 1;
            Game.CurrentScore.DepartureStation = PlayerFirstStationIndex;
            Game.CurrentScore.Maximum          = 0;
            for (int i = 0; i < Game.Stations.Length; i++)
            {
                if (i != PlayerFirstStationIndex & Game.PlayerStopsAtStation(i))
                {
                    if (i == 0 || Game.Stations[i - 1].Type != StationType.ChangeEnds)
                    {
                        Game.CurrentScore.Maximum += Game.ScoreValueStationArrival;
                    }
                }
            }
            if (Game.CurrentScore.Maximum <= 0)
            {
                Game.CurrentScore.Maximum = Game.ScoreValueStationArrival;
            }
            // signals
            if (Game.Sections.Length > 0)
            {
                Game.UpdateSection(Game.Sections.Length - 1);
            }
            // move train in position
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                double p;
                if (i == TrainManager.PlayerTrain.TrainIndex)
                {
                    p = PlayerFirstStationPosition;
                }
                else if (TrainManager.Trains[i].State == TrainManager.TrainState.Bogus)
                {
                    p = Game.BogusPretrainInstructions[0].TrackPosition;
                    TrainManager.Trains[i].AI = new Game.BogusPretrainAI(TrainManager.Trains[i]);
                }
                else
                {
                    p = OtherFirstStationPosition;
                }
                for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                {
                    TrainManager.Trains[i].Cars[j].Move(p, 0.01);
                }
            }
            // timetable
            if (Timetable.DefaultTimetableDescription.Length == 0)
            {
                Timetable.DefaultTimetableDescription = Game.LogTrainName;
            }

            // initialize camera
            if (World.CameraRestriction == World.CameraRestrictionMode.NotAvailable)
            {
                World.CameraMode = World.CameraViewMode.InteriorLookAhead;
            }
            //Place the initial camera in the driver car
            TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].UpdateCamera();
            World.CameraTrackFollower.Update(-1.0, true, false);
            ObjectManager.UpdateVisibility(World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z);
            World.CameraSavedExterior = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-2.5, 1.5, -15.0), 0.3, -0.2, 0.0, PlayerFirstStationPosition, 1.0);
            World.CameraSavedTrack    = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-3.0, 2.5, 0.0), 0.3, 0.0, 0.0, TrainManager.PlayerTrain.Cars[0].FrontAxle.Follower.TrackPosition - 10.0, 1.0);
            // signalling sections
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                int s = TrainManager.Trains[i].CurrentSectionIndex;
                Game.Sections[s].Enter(TrainManager.Trains[i]);
            }
            if (Game.Sections.Length > 0)
            {
                Game.UpdateSection(Game.Sections.Length - 1);
            }
            // fast-forward until start time
            {
                Game.MinimalisticSimulation = true;
                const double w = 0.25;
                double       u = Game.StartupTime - Game.SecondsSinceMidnight;
                if (u > 0)
                {
                    while (true)
                    {
                        double v = u < w ? u : w; u -= v;
                        Game.SecondsSinceMidnight += v;
                        TrainManager.UpdateTrains(v);
                        if (u <= 0.0)
                        {
                            break;
                        }
                        TotalTimeElapsedForSectionUpdate += v;
                        if (TotalTimeElapsedForSectionUpdate >= 1.0)
                        {
                            if (Game.Sections.Length > 0)
                            {
                                Game.UpdateSection(Game.Sections.Length - 1);
                            }
                            TotalTimeElapsedForSectionUpdate = 0.0;
                        }
                    }
                }
                Game.MinimalisticSimulation = false;
            }
            // animated objects
            ObjectManager.UpdateAnimatedWorldObjects(0.0, true);
            TrainManager.UpdateTrainObjects(0.0, true);
            //HACK: This function calls a single update on all objects attached to the player's train
            //      but ignores any specified damping so that all needles etc. are in the correct place
            //      for the first frame, rather than spinning wildly to get to the starting point.
            TrainManager.PlayerTrain.UpdateCabObjects();
            // timetable
            if (TrainManager.PlayerTrain.Station >= 0)
            {
                Timetable.UpdateCustomTimetable(Game.Stations[TrainManager.PlayerTrain.Station].TimetableDaytimeTexture, Game.Stations[TrainManager.PlayerTrain.Station].TimetableNighttimeTexture);
                if (Timetable.CustomObjectsUsed != 0 & Timetable.CustomTimetableAvailable && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.AutoGenerated && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.None)
                {
                    Timetable.CurrentTimetable = Timetable.TimetableState.Custom;
                }
            }
            //Create AI driver for the player train if specified via the commmand line
            if (Game.InitialAIDriver == true)
            {
                TrainManager.PlayerTrain.AI = new Game.SimpleHumanDriverAI(TrainManager.PlayerTrain);
                if (TrainManager.PlayerTrain.Plugin != null && !TrainManager.PlayerTrain.Plugin.SupportsAI)
                {
                    Game.AddMessage(Interface.GetInterfaceString("notification_aiunable"), MessageManager.MessageDependency.None, Interface.GameMode.Expert,
                                    OpenBveApi.Colors.MessageColor.White, Game.SecondsSinceMidnight + 10.0, null);
                }
            }

            // warnings / errors
            if (Interface.MessageCount != 0)
            {
                int filesNotFound = 0;
                int errors        = 0;
                int warnings      = 0;
                for (int i = 0; i < Interface.MessageCount; i++)
                {
                    if (Interface.Messages[i].FileNotFound)
                    {
                        filesNotFound++;
                    }
                    else if (Interface.Messages[i].Type == Interface.MessageType.Error)
                    {
                        errors++;
                    }
                    else if (Interface.Messages[i].Type == Interface.MessageType.Warning)
                    {
                        warnings++;
                    }
                }
                string NotFound = null;
                string Messages = null;
                if (filesNotFound != 0)
                {
                    NotFound = filesNotFound.ToString() + " file(s) not found";
                    Game.AddMessage(NotFound, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null);
                }
                if (errors != 0 & warnings != 0)
                {
                    Messages = errors.ToString() + " error(s), " + warnings.ToString() + " warning(s)";
                    Game.AddMessage(Messages, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null);
                }
                else if (errors != 0)
                {
                    Messages = errors.ToString() + " error(s)";
                    Game.AddMessage(Messages, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null);
                }
                else
                {
                    Messages = warnings.ToString() + " warning(s)";
                    Game.AddMessage(Messages, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null);
                }
                Game.RouteInformation.FilesNotFound     = NotFound;
                Game.RouteInformation.ErrorsAndWarnings = Messages;
                //Print the plugin error encountered (If any) for 10s
                //This must be done after the simulation has init, as otherwise the timeout doesn't work
                if (Loading.PluginError != null)
                {
                    Game.AddMessage(Loading.PluginError, MessageManager.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0, null);
                    Game.AddMessage(Interface.GetInterfaceString("errors_plugin_failure2"), MessageManager.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0, null);
                }
            }
            loadComplete          = true;
            RenderRealTimeElapsed = 0.0;
            RenderTimeElapsed     = 0.0;
            World.InitializeCameraRestriction();
            Loading.SimulationSetup = true;
            switch (Game.InitialViewpoint)
            {
            case 1:
                //Switch camera to exterior
                MainLoop.SaveCameraSettings();
                World.CameraMode = World.CameraViewMode.Exterior;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                }
                //Make bogies visible
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                }
                World.CameraAlignmentDirection = new World.CameraAlignment();
                World.CameraAlignmentSpeed     = new World.CameraAlignment();
                MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;

            case 2:
                //Switch camera to track
                MainLoop.SaveCameraSettings();
                World.CameraMode = World.CameraViewMode.Track;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                }

                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                }

                World.CameraAlignmentDirection = new World.CameraAlignment();
                World.CameraAlignmentSpeed     = new World.CameraAlignment();
                MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;

            case 3:
                //Switch camera to flyby
                MainLoop.SaveCameraSettings();
                World.CameraMode = World.CameraViewMode.FlyBy;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                }

                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                }

                World.CameraAlignmentDirection = new World.CameraAlignment();
                World.CameraAlignmentSpeed     = new World.CameraAlignment();
                MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;

            case 4:
                //Switch camera to flyby
                MainLoop.SaveCameraSettings();
                World.CameraMode = World.CameraViewMode.FlyByZooming;
                MainLoop.RestoreCameraSettings();
                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior);
                }

                for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++)
                {
                    TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0);
                    TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0);
                }

                World.CameraAlignmentDirection = new World.CameraAlignment();
                World.CameraAlignmentSpeed     = new World.CameraAlignment();
                MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange);
                World.UpdateAbsoluteCamera(0.0);
                World.UpdateViewingDistances();
                break;
            }
        }
Пример #31
0
        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            TimeFactor = MainLoop.TimeFactor;
            // timer
            double RealTimeElapsed;
            double TimeElapsed;

            if (Game.SecondsSinceMidnight >= Game.StartupTime)
            {
                RealTimeElapsed = CPreciseTimer.GetElapsedTime();
                TimeElapsed     = RealTimeElapsed * (double)TimeFactor;
                if (loadComplete && !firstFrame)
                {
                    //Our current in-game time is equal to or greater than the startup time, but the first frame has not yet been processed
                    //Therefore, reset the timer to zero as time consuming texture loads may cause us to be late at the first station
                    RealTimeElapsed = 0.0;
                    TimeElapsed     = 0.0;
                    firstFrame      = true;
                }
            }
            else
            {
                RealTimeElapsed = 0.0;
                TimeElapsed     = Game.StartupTime - Game.SecondsSinceMidnight;
            }

            //We only want to update the simulation if we aren't in a menu
            if (Game.CurrentInterface == Game.InterfaceType.Normal)
            {
#if DEBUG
                //If we're in debug mode and a frame takes greater than a second to render, we can safely assume that VS has hit a breakpoint
                //Check this and the sim no longer barfs because the update time was too great
                if (RealTimeElapsed > 1)
                {
                    RealTimeElapsed = 0.0;
                    TimeElapsed     = 0.0;
                }
#endif
                TotalTimeElapsedForInfo          += TimeElapsed;
                TotalTimeElapsedForSectionUpdate += TimeElapsed;


                if (TotalTimeElapsedForSectionUpdate >= 1.0)
                {
                    if (Game.Sections.Length != 0)
                    {
                        Game.UpdateSection(Game.Sections.Length - 1);
                    }
                    TotalTimeElapsedForSectionUpdate = 0.0;
                }

                // events

                // update simulation in chunks
                {
                    const double chunkTime = 1.0 / 2.0;
                    if (TimeElapsed <= chunkTime)
                    {
                        Game.SecondsSinceMidnight += TimeElapsed;
                        TrainManager.UpdateTrains(TimeElapsed);
                    }
                    else
                    {
                        const int maxChunks = 2;
                        int       chunks    = Math.Min((int)Math.Round(TimeElapsed / chunkTime), maxChunks);
                        double    time      = TimeElapsed / (double)chunks;
                        for (int i = 0; i < chunks; i++)
                        {
                            Game.SecondsSinceMidnight += time;
                            TrainManager.UpdateTrains(time);
                        }
                    }
                }
                Game.CurrentScore.Update(TimeElapsed);
                Game.UpdateMessages();
                Game.UpdateScoreMessages(TimeElapsed);
            }
            RenderTimeElapsed     += TimeElapsed;
            RenderRealTimeElapsed += RealTimeElapsed;
        }
Пример #32
0
        /// <summary>Jumps a train to a new station</summary>
        /// <param name="train">The train</param>
        /// <param name="stationIndex">The zero-based index of the station</param>
        internal static void JumpTrain(Train train, int stationIndex)
        {
            train.SafetySystems.PassAlarm.Halt();
            int currentTrackElement = train.Cars[0].FrontAxle.Follower.LastTrackElement;

            if (train.IsPlayerTrain)
            {
                for (int i = 0; i < ObjectManager.AnimatedWorldObjects.Length; i++)
                {
                    var obj = ObjectManager.AnimatedWorldObjects[i] as OpenBveApi.Objects.TrackFollowingObject;
                    if (obj != null)
                    {
                        //Track followers should be reset if we jump between stations
                        obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.FrontAxlePosition;
                        obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.RearAxlePosition;
                        obj.FrontAxleFollower.UpdateWorldCoordinates(false);
                        obj.RearAxleFollower.UpdateWorldCoordinates(false);
                    }
                }
            }
            train.StationState = TrainStopState.Jumping;
            int stopIndex = Program.CurrentRoute.Stations[stationIndex].GetStopIndex(train.NumberOfCars);

            if (stopIndex >= 0)
            {
                if (train.IsPlayerTrain)
                {
                    if (train.Plugin != null)
                    {
                        train.Plugin.BeginJump((OpenBveApi.Runtime.InitializationModes)Game.TrainStart);
                    }
                }
                for (int h = 0; h < train.Cars.Length; h++)
                {
                    train.Cars[h].CurrentSpeed = 0.0;
                }
                double d = Program.CurrentRoute.Stations[stationIndex].Stops[stopIndex].TrackPosition - train.Cars[0].FrontAxle.Follower.TrackPosition + train.Cars[0].FrontAxle.Position - 0.5 * train.Cars[0].Length;
                if (train.IsPlayerTrain)
                {
                    SoundsBase.SuppressSoundEvents = true;
                }
                while (d != 0.0)
                {
                    double x;
                    if (Math.Abs(d) > 1.0)
                    {
                        x = (double)Math.Sign(d);
                    }
                    else
                    {
                        x = d;
                    }
                    for (int h = 0; h < train.Cars.Length; h++)
                    {
                        train.Cars[h].Move(x);
                    }
                    if (Math.Abs(d) >= 1.0)
                    {
                        d -= x;
                    }
                    else
                    {
                        break;
                    }
                }
                if (train.IsPlayerTrain)
                {
                    TrainManager.UnderailTrains();
                    SoundsBase.SuppressSoundEvents = false;
                }
                if (train.Handles.EmergencyBrake.Driver)
                {
                    train.ApplyNotch(0, false, 0, true);
                }
                else
                {
                    train.ApplyNotch(0, false, train.Handles.Brake.MaximumNotch, false);
                    train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                }
                if (Program.CurrentRoute.Sections.Length > 0)
                {
                    Program.CurrentRoute.UpdateAllSections();
                }
                if (train.IsPlayerTrain)
                {
                    if (Game.CurrentScore.ArrivalStation <= stationIndex)
                    {
                        Game.CurrentScore.ArrivalStation = stationIndex + 1;
                    }
                }
                if (train.IsPlayerTrain)
                {
                    if (Program.CurrentRoute.Stations[stationIndex].ArrivalTime >= 0.0)
                    {
                        Program.CurrentRoute.SecondsSinceMidnight = Program.CurrentRoute.Stations[stationIndex].ArrivalTime;
                    }
                    else if (Program.CurrentRoute.Stations[stationIndex].DepartureTime >= 0.0)
                    {
                        Program.CurrentRoute.SecondsSinceMidnight = Program.CurrentRoute.Stations[stationIndex].DepartureTime - Program.CurrentRoute.Stations[stationIndex].StopTime;
                    }
                }
                for (int i = 0; i < train.Cars.Length; i++)
                {
                    train.Cars[i].Doors[0].AnticipatedOpen = Program.CurrentRoute.Stations[stationIndex].OpenLeftDoors;
                    train.Cars[i].Doors[1].AnticipatedOpen = Program.CurrentRoute.Stations[stationIndex].OpenRightDoors;
                }
                if (train.IsPlayerTrain)
                {
                    Game.CurrentScore.DepartureStation = stationIndex;
                    Program.Renderer.CurrentInterface  = InterfaceType.Normal;
                }
                ObjectManager.UpdateAnimatedWorldObjects(0.0, true);
                TrainManager.UpdateTrainObjects(0.0, true);
                if (train.IsPlayerTrain)
                {
                    if (train.Plugin != null)
                    {
                        train.Plugin.EndJump();
                    }
                }
                train.StationState = TrainStopState.Pending;
                if (train.IsPlayerTrain)
                {
                    train.LastStation = stationIndex;
                }
                int newTrackElement = train.Cars[0].FrontAxle.Follower.LastTrackElement;
                if (newTrackElement < currentTrackElement)
                {
                    for (int i = newTrackElement; i < currentTrackElement; i++)
                    {
                        for (int j = 0; j < Program.CurrentHost.Tracks[0].Elements[i].Events.Length; j++)
                        {
                            Program.CurrentHost.Tracks[0].Elements[i].Events[j].Reset();
                        }
                    }
                }
            }
        }
Пример #33
0
        private static void LoadEverythingThreaded()
        {
            Program.FileSystem.AppendToLogFile("Loading route file: " + CurrentRouteFile);
            Program.FileSystem.AppendToLogFile("INFO: Route file hash " + CsvRwRouteParser.GetChecksum(CurrentRouteFile));
            string RailwayFolder = GetRailwayFolder(CurrentRouteFile);
            string ObjectFolder  = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object");
            string SoundFolder   = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound");

            Game.Reset(true, false);
            Game.MinimalisticSimulation = true;
            // screen
            Program.Renderer.Camera.CurrentMode = CameraViewMode.Interior;
            //First, check the format of the route file
            //RW routes were written for BVE1 / 2, and have a different command syntax
            bool IsRW = CsvRwRouteParser.isRWFile(CurrentRouteFile);

            Program.FileSystem.AppendToLogFile("Route file format is: " + (IsRW ? "RW" : "CSV"));
            CsvRwRouteParser.ParseRoute(CurrentRouteFile, IsRW, CurrentRouteEncoding, CurrentTrainFolder, ObjectFolder, SoundFolder, false);
            Thread createIllustrations = new Thread(Game.RouteInformation.LoadInformation)
            {
                IsBackground = true
            };

            createIllustrations.Start();
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Program.CurrentRoute.Atmosphere.CalculateSeaLevelConstants();
            if (Program.CurrentRoute.BogusPreTrainInstructions.Length != 0)
            {
                double t = Program.CurrentRoute.BogusPreTrainInstructions[0].Time;
                double p = Program.CurrentRoute.BogusPreTrainInstructions[0].TrackPosition;
                for (int i = 1; i < Program.CurrentRoute.BogusPreTrainInstructions.Length; i++)
                {
                    if (Program.CurrentRoute.BogusPreTrainInstructions[i].Time > t)
                    {
                        t = Program.CurrentRoute.BogusPreTrainInstructions[i].Time;
                    }
                    else
                    {
                        t += 1.0;
                        Program.CurrentRoute.BogusPreTrainInstructions[i].Time = t;
                    }
                    if (Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition > p)
                    {
                        p = Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition;
                    }
                    else
                    {
                        p += 1.0;
                        Program.CurrentRoute.BogusPreTrainInstructions[i].TrackPosition = p;
                    }
                }
            }
            World.CameraTrackFollower = new TrackFollower(Program.CurrentHost)
            {
                Train = null, Car = null
            };
            if (Program.CurrentRoute.Stations.Length == 1)
            {
                //Log the fact that only a single station is present, as this is probably not right
                Program.FileSystem.AppendToLogFile("The processed route file only contains a single station.");
            }
            Program.FileSystem.AppendToLogFile("Route file loaded successfully.");
            RouteProgress = 1.0;
            // initialize trains
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            TrainManager.Trains = new TrainManager.Train[Game.PrecedingTrainTimeDeltas.Length + 1 + (Program.CurrentRoute.BogusPreTrainInstructions.Length != 0 ? 1 : 0)];
            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                if (k == TrainManager.Trains.Length - 1 & Program.CurrentRoute.BogusPreTrainInstructions.Length != 0)
                {
                    TrainManager.Trains[k] = new TrainManager.Train(TrainState.Bogus);
                }
                else
                {
                    TrainManager.Trains[k] = new TrainManager.Train(TrainState.Pending);
                }
            }
            TrainManager.PlayerTrain = TrainManager.Trains[Game.PrecedingTrainTimeDeltas.Length];

            UnifiedObject[] CarObjects     = null;
            UnifiedObject[] BogieObjects   = null;
            UnifiedObject[] CouplerObjects = null;

            // load trains
            double TrainProgressMaximum = 0.7 + 0.3 * (double)TrainManager.Trains.Length;

            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                //Sleep for 20ms to allow route loading locks to release
                Thread.Sleep(20);
                if (TrainManager.Trains[k].State == TrainState.Bogus)
                {
                    // bogus train
                    string TrainData = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility", "PreTrain"), "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, System.Text.Encoding.UTF8, TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainManager.Trains[k].InitializeCarSounds();
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.3 / TrainProgressMaximum;
                    TrainProgressCurrentSum   += TrainProgressCurrentWeight;
                }
                else
                {
                    TrainManager.Trains[k].TrainFolder = CurrentTrainFolder;
                    // real train
                    if (TrainManager.Trains[k].IsPlayerTrain)
                    {
                        Program.FileSystem.AppendToLogFile("Loading player train: " + TrainManager.Trains[k].TrainFolder);
                    }
                    else
                    {
                        Program.FileSystem.AppendToLogFile("Loading AI train: " + TrainManager.Trains[k].TrainFolder);
                    }
                    TrainProgressCurrentWeight = 0.1 / TrainProgressMaximum;
                    string TrainData = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.2 / TrainProgressMaximum;
                    SoundCfgParser.ParseSoundConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    // door open/close speed
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].OpenSound.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].OpenSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = 0.8;
                            }
                        }
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null & TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer != null)
                            {
                                Program.Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Doors[0].CloseSound.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Doors[1].CloseSound.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = 0.8;
                            }
                        }
                        const double f = 0.015;
                        const double g = 2.75;
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency  /= TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch;
                        TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency /= TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch;

                        /*
                         * Remove the following two lines, then the pitch at which doors play
                         * takes their randomized opening and closing times into account.
                         * */
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch  = 1.0;
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch = 1.0;
                    }
                }
                // add panel section
                if (TrainManager.Trains[k].IsPlayerTrain)
                {
                    TrainProgressCurrentWeight = 0.7 / TrainProgressMaximum;
                    TrainManager.ParsePanelConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    Program.FileSystem.AppendToLogFile("Train panel loaded sucessfully.");
                }
                // add exterior section
                if (TrainManager.Trains[k].State != TrainState.Bogus)
                {
                    bool LoadObjects = false;
                    if (CarObjects == null)
                    {
                        CarObjects     = new UnifiedObject[TrainManager.Trains[k].Cars.Length];
                        BogieObjects   = new UnifiedObject[TrainManager.Trains[k].Cars.Length * 2];
                        CouplerObjects = new UnifiedObject[TrainManager.Trains[k].Cars.Length];
                        LoadObjects    = true;
                    }
                    string tXml = OpenBveApi.Path.CombineFile(TrainManager.Trains[k].TrainFolder, "train.xml");
                    if (System.IO.File.Exists(tXml))
                    {
                        TrainXmlParser.Parse(tXml, TrainManager.Trains[k], ref CarObjects, ref BogieObjects, ref CouplerObjects);
                    }
                    else
                    {
                        ExtensionsCfgParser.ParseExtensionsConfig(TrainManager.Trains[k].TrainFolder, CurrentTrainEncoding, ref CarObjects, ref BogieObjects, ref CouplerObjects, TrainManager.Trains[k], LoadObjects);
                    }
                    World.CameraCar = TrainManager.Trains[k].DriverCar;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    //Stores the current array index of the bogie object to add
                    //Required as there are two bogies per car, and we're using a simple linear array....
                    int currentBogieObject = 0;
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (CarObjects[i] == null)
                        {
                            // load default exterior object
                            string       file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                            StaticObject so   = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, false);
                            if (so == null)
                            {
                                CarObjects[i] = null;
                            }
                            else
                            {
                                double sx = TrainManager.Trains[k].Cars[i].Width;
                                double sy = TrainManager.Trains[k].Cars[i].Height;
                                double sz = TrainManager.Trains[k].Cars[i].Length;
                                so.ApplyScale(sx, sy, sz);
                                CarObjects[i] = so;
                            }
                        }
                        if (CarObjects[i] != null)
                        {
                            // add object
                            TrainManager.Trains[k].Cars[i].LoadCarSections(CarObjects[i]);
                        }

                        if (CouplerObjects[i] != null)
                        {
                            TrainManager.Trains[k].Cars[i].Coupler.LoadCarSections(CouplerObjects[i]);
                        }
                        //Load bogie objects
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            TrainManager.Trains[k].Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                        }
                        currentBogieObject++;
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            TrainManager.Trains[k].Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                        }
                        currentBogieObject++;
                    }
                }
                // place cars
                TrainManager.Trains[k].PlaceCars(0.0);

                // configure ai / timetable
                if (TrainManager.Trains[k].IsPlayerTrain)
                {
                    TrainManager.Trains[k].TimetableDelta = 0.0;
                }
                else if (TrainManager.Trains[k].State != TrainState.Bogus)
                {
                    TrainManager.Trains[k].AI                  = new Game.SimpleHumanDriverAI(TrainManager.Trains[k]);
                    TrainManager.Trains[k].TimetableDelta      = Game.PrecedingTrainTimeDeltas[k];
                    TrainManager.Trains[k].Specs.DoorOpenMode  = TrainManager.DoorMode.Manual;
                    TrainManager.Trains[k].Specs.DoorCloseMode = TrainManager.DoorMode.Manual;
                }
            }

            /*
             * HACK: Store the TrainManager.Trains reference in the RouteManager also
             *		 Note that this may change when the TrainManager is separated from the lump
             *       Remember not to modify via this ref
             */
            // ReSharper disable once CoVariantArrayConversion
            Program.CurrentRoute.Trains = TrainManager.Trains;
            TrainProgress = 1.0;
            // finished created objects
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Array.Resize(ref ObjectManager.AnimatedWorldObjects, ObjectManager.AnimatedWorldObjectsUsed);
            // update sections
            if (Program.CurrentRoute.Sections.Length > 0)
            {
                Program.CurrentRoute.UpdateAllSections();
            }
            // load plugin
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                if (TrainManager.Trains[i].State != TrainState.Bogus)
                {
                    if (TrainManager.Trains[i].IsPlayerTrain)
                    {
                        if (!TrainManager.Trains[i].LoadCustomPlugin(TrainManager.Trains[i].TrainFolder, CurrentTrainEncoding))
                        {
                            TrainManager.Trains[i].LoadDefaultPlugin(TrainManager.Trains[i].TrainFolder);
                        }
                    }
                    else
                    {
                        TrainManager.Trains[i].LoadDefaultPlugin(TrainManager.Trains[i].TrainFolder);
                    }
                }
            }
        }
Пример #34
0
            internal override void Trigger(double TimeElapsed)
            {
                // Trains need to stop more than 2 points.
                if (Data == null || Data.Count < 2 || SecondsSinceMidnight == TimeLastProcessed)
                {
                    return;
                }

                // Initialize
                if (TimeLastProcessed == 0.0)
                {
                    SetupTravelData(SecondsSinceMidnight);
                    CheckTravelData(SecondsSinceMidnight);
                    CurrentPosition = Data[0].StopPosition;
                }

                TimeLastProcessed = SecondsSinceMidnight;

                // Calculate the position where the train is at the present time.
                double DeltaT;
                double Position       = Data[0].StopPosition;
                int    RailIndex      = Data[0].RailIndex;
                bool   OpenLeftDoors  = false;
                bool   OpenRightDoors = false;

                if (SecondsSinceMidnight >= Data[0].ArrivalTime)
                {
                    OpenLeftDoors  = Data[0].OpenLeftDoors;
                    OpenRightDoors = Data[0].OpenRightDoors;
                }

                if (SecondsSinceMidnight >= Data[0].ClosingDoorsStartTime)
                {
                    OpenLeftDoors  = false;
                    OpenRightDoors = false;
                }

                // The start point does not slow down. Acceleration only.
                if (SecondsSinceMidnight >= Data[0].DepartureTime)
                {
                    if (SecondsSinceMidnight < Data[0].AccelerationEndTime)
                    {
                        DeltaT = SecondsSinceMidnight - Data[0].DepartureTime;
                    }
                    else
                    {
                        DeltaT = Data[0].AccelerationEndTime - Data[0].DepartureTime;
                    }
                    Position += (int)Data[0].Direction * (0.5 * Data[0].Accelerate * Math.Pow(DeltaT, 2.0));
                }

                for (int i = 1; i < Data.Count; i++)
                {
                    if (SecondsSinceMidnight >= Data[i - 1].AccelerationEndTime)
                    {
                        if (SecondsSinceMidnight < Data[i].DecelerationStartTime)
                        {
                            DeltaT = SecondsSinceMidnight - Data[i - 1].AccelerationEndTime;
                        }
                        else
                        {
                            DeltaT = Data[i].DecelerationStartTime - Data[i - 1].AccelerationEndTime;
                        }
                        Position += (int)Data[i - 1].Direction * (Data[i - 1].TargetSpeed * DeltaT);
                    }

                    if (SecondsSinceMidnight >= Data[i].DecelerationStartTime)
                    {
                        if (SecondsSinceMidnight < Data[i].ArrivalTime)
                        {
                            DeltaT = SecondsSinceMidnight - Data[i].DecelerationStartTime;
                        }
                        else
                        {
                            DeltaT = Data[i].ArrivalTime - Data[i].DecelerationStartTime;
                        }
                        Position += (int)Data[i - 1].Direction * (Data[i - 1].TargetSpeed * DeltaT - 0.5 * Data[i].Decelerate * Math.Pow(DeltaT, 2.0));
                    }

                    if (SecondsSinceMidnight >= Data[i].ArrivalTime)
                    {
                        OpenLeftDoors  = Data[i].OpenLeftDoors;
                        OpenRightDoors = Data[i].OpenRightDoors;
                    }

                    if (SecondsSinceMidnight >= Data[i].ClosingDoorsStartTime)
                    {
                        OpenLeftDoors  = false;
                        OpenRightDoors = false;
                    }

                    if (SecondsSinceMidnight >= Data[i].DepartureTime)
                    {
                        if (SecondsSinceMidnight < Data[i].AccelerationEndTime)
                        {
                            DeltaT = SecondsSinceMidnight - Data[i].DepartureTime;
                        }
                        else
                        {
                            DeltaT = Data[i].AccelerationEndTime - Data[i].DepartureTime;
                        }
                        Position += (int)Data[i].Direction * (0.5 * Data[i].Accelerate * Math.Pow(DeltaT, 2.0));
                        RailIndex = Data[i].RailIndex;
                    }
                }

                // Calculate the travel distance of the train.
                double Delta = Position - CurrentPosition;

                CurrentPosition = Position;

                // Set the state quantity of the train.
                if (Delta < 0)
                {
                    Train.Handles.Reverser.Driver = TrainManager.ReverserPosition.Reverse;
                }
                else if (Delta > 0)
                {
                    Train.Handles.Reverser.Driver = TrainManager.ReverserPosition.Forwards;
                }
                Train.Handles.Reverser.Actual = Train.Handles.Reverser.Driver;

                TrainManager.OpenTrainDoors(Train, OpenLeftDoors, OpenRightDoors);
                TrainManager.CloseTrainDoors(Train, !OpenLeftDoors, !OpenRightDoors);

                foreach (var Car in Train.Cars)
                {
                    Car.FrontAxle.Follower.TrackIndex            = RailIndex;
                    Car.RearAxle.Follower.TrackIndex             = RailIndex;
                    Car.FrontBogie.FrontAxle.Follower.TrackIndex = RailIndex;
                    Car.FrontBogie.RearAxle.Follower.TrackIndex  = RailIndex;
                    Car.RearBogie.FrontAxle.Follower.TrackIndex  = RailIndex;
                    Car.RearBogie.RearAxle.Follower.TrackIndex   = RailIndex;
                    Car.Move(Delta);
                    if (TimeElapsed != 0.0)
                    {
                        Car.Specs.CurrentSpeed          = Delta / TimeElapsed;
                        Car.Specs.CurrentPerceivedSpeed = Car.Specs.CurrentSpeed;
                        if (Car.Specs.CurrentPerceivedSpeed < 0)
                        {
                            Car.Specs.CurrentAcceleration = -(Car.Specs.CurrentSpeed / TimeElapsed);
                        }
                        else
                        {
                            Car.Specs.CurrentAcceleration = Car.Specs.CurrentSpeed / TimeElapsed;
                        }
                        Car.Specs.CurrentAccelerationOutput = Car.Specs.CurrentAcceleration;
                    }
                    else
                    {
                        Car.Specs.CurrentSpeed              = 0.0;
                        Car.Specs.CurrentPerceivedSpeed     = 0.0;
                        Car.Specs.CurrentAcceleration       = 0.0;
                        Car.Specs.CurrentAccelerationOutput = 0.0;
                    }
                }

                Train.Specs.CurrentAverageSpeed        = Train.Cars[0].Specs.CurrentSpeed;
                Train.Specs.CurrentAverageAcceleration = Train.Cars[0].Specs.CurrentAcceleration;

                // Dispose the train if it is past the leave time of the train
                if (LeaveTime > AppearanceTime && SecondsSinceMidnight >= LeaveTime)
                {
                    Train.Dispose();
                }
            }
Пример #35
0
			internal double Perform(TrainManager.Train Train, int CarIndex, World.Vector3D Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed) {
				ExecuteFunctionScript(this, Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
				return this.LastResult;
			}
Пример #36
0
 // load bve 4 sound
 private static void LoadBve4Sound(string FileName, string TrainPath, System.Text.Encoding Encoding, TrainManager.Train train)
 {
     // set sound positions and radii
     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 front = new Vector3(0.0, 0.0, 0.5 * train.Cars[train.DriverCar].Length);
     Vector3 cab = new Vector3(-train.Cars[train.DriverCar].DriverX, train.Cars[train.DriverCar].DriverY, train.Cars[train.DriverCar].DriverZ - 0.5);
     Vector3 panel = new Vector3(train.Cars[train.DriverCar].DriverX, train.Cars[train.DriverCar].DriverY, train.Cars[train.DriverCar].DriverZ + 1.0);
     double large = 30.0;
     double medium = 10.0;
     double small = 5.0;
     double tiny = 2.0;
     LoadNoSound(train);
     // parse configuration file
     System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
     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();
         }
     }
     if (Lines.Length < 1 || string.Compare(Lines[0], "version 1.0", StringComparison.OrdinalIgnoreCase) != 0) {
         Interface.AddMessage(Interface.MessageType.Error, false, "Invalid file format encountered in " + FileName + ". The first line is expected to be \"Version 1.0\".");
     }
     string[] MotorFiles = new string[] { };
     double invfac = Lines.Length == 0 ? Loading.TrainProgressCurrentWeight : Loading.TrainProgressCurrentWeight / (double)Lines.Length;
     for (int i = 0; i < Lines.Length; i++) {
         Loading.TrainProgress = Loading.TrainProgressCurrentSum + invfac * (double)i;
         if ((i & 7) == 0) {
             System.Threading.Thread.Sleep(1);
             if (Loading.Cancel) return;
         }
         switch (Lines[i].ToLowerInvariant()) {
             case "[run]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         int k;
                         if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             if (k >= 0) {
                                 for (int c = 0; c < train.Cars.Length; c++) {
                                     int n = train.Cars[c].Sounds.Run.Length;
                                     if (k >= n) {
                                         Array.Resize<TrainManager.CarSound>(ref train.Cars[c].Sounds.Run, k + 1);
                                         for (int h = n; h < k; h++) {
                                             train.Cars[c].Sounds.Run[h] = TrainManager.CarSound.Empty;
                                         }
                                     }
                                     train.Cars[c].Sounds.Run[k] = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                 }
                             } else {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "Index must be greater or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                             }
                         }
                     } i++;
                 } i--; break;
             case "[flange]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         int k;
                         if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             if (k >= 0) {
                                 for (int c = 0; c < train.Cars.Length; c++) {
                                     int n = train.Cars[c].Sounds.Flange.Length;
                                     if (k >= n) {
                                         Array.Resize<TrainManager.CarSound>(ref train.Cars[c].Sounds.Flange, k + 1);
                                         for (int h = n; h < k; h++) {
                                             train.Cars[c].Sounds.Flange[h] = TrainManager.CarSound.Empty;
                                         }
                                     }
                                     train.Cars[c].Sounds.Flange[k] = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                 }
                             } else {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "Index must be greater or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                             }
                         }
                     } i++;
                 } i--; break;
             case "[motor]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         int k;
                         if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             if (k >= 0) {
                                 if (k >= MotorFiles.Length) {
                                     Array.Resize<string>(ref MotorFiles, k + 1);
                                 }
                                 MotorFiles[k] = OpenBveApi.Path.CombineFile(TrainPath, b);
                                 if (!System.IO.File.Exists(MotorFiles[k])) {
                                     Interface.AddMessage(Interface.MessageType.Error, true, "File " + MotorFiles[k] + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     MotorFiles[k] = null;
                                 }
                             } else {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "Index is invalid at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                             }
                         }
                     } i++;
                 } i--; break;
             case "[switch]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else if (a == "0") {
                             for (int c = 0; c < train.Cars.Length; c++) {
                                 Vector3 frontaxle = new Vector3(0.0, 0.0, train.Cars[c].FrontAxlePosition);
                                 Vector3 rearaxle = new Vector3(0.0, 0.0, train.Cars[c].RearAxlePosition);
                                 train.Cars[c].Sounds.PointFrontAxle = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), frontaxle, small);
                                 train.Cars[c].Sounds.PointRearAxle = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), rearaxle, small);
                             }
                         } else {
                             Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported index " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         }
                     } i++;
                 } i--; break;
             case "[brake]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "bc release high":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.AirHigh = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, small);
                                     } break;
                                 case "bc release":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.Air = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, small);
                                     } break;
                                 case "bc release full":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.AirZero = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, small);
                                     } break;
                                 case "emergency":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.EmrBrake = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                     } break;
                                 case "bp decomp":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.Brake = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, small);
                                     } break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[compressor]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             for (int c = 0; c < train.Cars.Length; c++) {
                                 if (train.Cars[c].Specs.AirBrake.Type == TrainManager.AirBrakeType.Main) {
                                     switch (a.ToLowerInvariant()) {
                                         case "attack":
                                             train.Cars[c].Sounds.CpStart = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                             break;
                                         case "loop":
                                             train.Cars[c].Sounds.CpLoop = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                             break;
                                         case "release":
                                             train.Cars[c].Sounds.CpEnd = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                             break;
                                         default:
                                             Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                             break;
                                     }
                                 }
                             }
                         }
                     } i++;
                 } i--; break;
             case "[suspension]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "left":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.SpringL = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), left, small);
                                     } break;
                                 case "right":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.SpringR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), right, small);
                                     } break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[horn]":
                 i++;
                 while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "primary":
                                     train.Cars[train.DriverCar].Sounds.Horns[0].Sound = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), front, large);
                                     train.Cars[train.DriverCar].Sounds.Horns[0].Loop = false;
                                     break;
                                 case "secondary":
                                     train.Cars[train.DriverCar].Sounds.Horns[1].Sound = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), front, large);
                                     train.Cars[train.DriverCar].Sounds.Horns[1].Loop = false;
                                     break;
                                 case "music":
                                     train.Cars[train.DriverCar].Sounds.Horns[2].Sound = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), front, medium);
                                     train.Cars[train.DriverCar].Sounds.Horns[2].Loop = true;
                                     break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[door]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "open left":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.DoorOpenL = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), left, small);
                                     } break;
                                 case "open right":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.DoorOpenR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), left, small);
                                     } break;
                                 case "close left":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.DoorCloseL = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), left, small);
                                     } break;
                                 case "close right":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.DoorCloseR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), left, small);
                                     } break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[ats]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             int k;
                             if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k)) {
                                 Interface.AddMessage(Interface.MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                             } else {
                                 if (k >= 0) {
                                     int n = train.Cars[train.DriverCar].Sounds.Plugin.Length;
                                     if (k >= n) {
                                         Array.Resize<TrainManager.CarSound>(ref train.Cars[train.DriverCar].Sounds.Plugin, k + 1);
                                         for (int h = n; h < k; h++) {
                                             train.Cars[train.DriverCar].Sounds.Plugin[h] = TrainManager.CarSound.Empty;
                                         }
                                     }
                                     train.Cars[train.DriverCar].Sounds.Plugin[k] = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                 } else {
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Index must be greater or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                 }
                             }
                         }
                     } i++;
                 } i--; break;
             case "[buzzer]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "correct":
                                     train.Cars[train.DriverCar].Sounds.Adjust = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[pilot lamp]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "on":
                                     train.Cars[train.DriverCar].Sounds.PilotLampOn = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "off":
                                     train.Cars[train.DriverCar].Sounds.PilotLampOff = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[brake handle]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "apply":
                                     train.Cars[train.DriverCar].Sounds.BrakeHandleApply = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "release":
                                     train.Cars[train.DriverCar].Sounds.BrakeHandleRelease = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "min":
                                     train.Cars[train.DriverCar].Sounds.BrakeHandleMin = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "max":
                                     train.Cars[train.DriverCar].Sounds.BrakeHandleMax = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[master controller]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "up":
                                     train.Cars[train.DriverCar].Sounds.MasterControllerUp = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "down":
                                     train.Cars[train.DriverCar].Sounds.MasterControllerDown = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "min":
                                     train.Cars[train.DriverCar].Sounds.MasterControllerMin = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "max":
                                     train.Cars[train.DriverCar].Sounds.MasterControllerMax = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[reverser]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "on":
                                     train.Cars[train.DriverCar].Sounds.ReverserOn = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 case "off":
                                     train.Cars[train.DriverCar].Sounds.ReverserOff = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, tiny);
                                     break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[breaker]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "on":
                                     train.Cars[train.DriverCar].Sounds.BreakerResume = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, small);
                                     break;
                                 case "off":
                                     train.Cars[train.DriverCar].Sounds.BreakerResumeOrInterrupt = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), panel, small);
                                     break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
             case "[others]":
                 i++; while (i < Lines.Length && !Lines[i].StartsWith("[", StringComparison.Ordinal)) {
                     int j = Lines[i].IndexOf("=");
                     if (j >= 0) {
                         string a = Lines[i].Substring(0, j).TrimEnd();
                         string b = Lines[i].Substring(j + 1).TrimStart();
                         if (b.Length == 0 || Interface.ContainsInvalidPathChars(b)) {
                             Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters or is empty at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                         } else {
                             switch (a.ToLowerInvariant()) {
                                 case "noise":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         if (train.Cars[c].Specs.IsMotorCar | c == train.DriverCar) {
                                             train.Cars[c].Sounds.Loop = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                         }
                                     } break;
                                 case "shoe":
                                     for (int c = 0; c < train.Cars.Length; c++) {
                                         train.Cars[c].Sounds.Rub = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, b), center, medium);
                                     } break;
                                 default:
                                     Interface.AddMessage(Interface.MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                     break;
                             }
                         }
                     } i++;
                 } i--; break;
         }
     }
     for (int i = 0; i < train.Cars.Length; i++) {
         train.Cars[i].Sounds.RunVolume = new double[train.Cars[i].Sounds.Run.Length];
         train.Cars[i].Sounds.FlangeVolume = new double[train.Cars[i].Sounds.Flange.Length];
     }
     // motor sound
     for (int c = 0; c < train.Cars.Length; c++) {
         if (train.Cars[c].Specs.IsMotorCar) {
             train.Cars[c].Sounds.Motor.Position = center;
             for (int i = 0; i < train.Cars[c].Sounds.Motor.Tables.Length; i++) {
                 train.Cars[c].Sounds.Motor.Tables[i].Buffer = null;
                 train.Cars[c].Sounds.Motor.Tables[i].Source = null;
                 for (int j = 0; j < train.Cars[c].Sounds.Motor.Tables[i].Entries.Length; j++) {
                     int index = train.Cars[c].Sounds.Motor.Tables[i].Entries[j].SoundIndex;
                     if (index >= 0 && index < MotorFiles.Length && MotorFiles[index] != null) {
                         train.Cars[c].Sounds.Motor.Tables[i].Entries[j].Buffer = Sounds.RegisterBuffer(MotorFiles[index], medium);
                     }
                 }
             }
         }
     }
 }
Пример #37
0
		/// <summary>Loads a custom plugin for the specified train.</summary>
		/// <param name="train">The train to attach the plugin to.</param>
		/// <param name="trainFolder">The absolute path to the train folder.</param>
		/// <param name="encoding">The encoding to be used.</param>
		/// <returns>Whether the plugin was loaded successfully.</returns>
		internal static bool LoadCustomPlugin(TrainManager.Train train, string trainFolder, System.Text.Encoding encoding) {
			string config = OpenBveApi.Path.CombineFile(trainFolder, "ats.cfg");
			if (!System.IO.File.Exists(config)) {
				return false;
			}
			string[] lines = System.IO.File.ReadAllLines(config, encoding);
			if (lines.Length == 0) {
				return false;
			}
			string file = OpenBveApi.Path.CombineFile(trainFolder, lines[0]);
			string title = System.IO.Path.GetFileName(file);
			if (!System.IO.File.Exists(file)) {
				Interface.AddMessage(Interface.MessageType.Error, true, "The train plugin " + title + " could not be found in " + config);
				return false;
			}
			Program.AppendToLogFile("Loading train plugin: " + file);
			bool success = LoadPlugin(train, file, trainFolder);
			if (success == false)
			{
				Loading.PluginError = Interface.GetInterfaceString("errors_plugin_failure1").Replace("[plugin]", file);
			}
			else
			{
				Program.AppendToLogFile("Train plugin loaded successfully.");
			}
			return success;
		}
Пример #38
0
		// create element
		private static int CreateElement(TrainManager.Train Train, double Left, double Top, double Width, double Height, double FullWidth, double FullHeight, double WorldLeft, double WorldTop, double WorldWidth, double WorldHeight, double WorldZ, double DriverX, double DriverY, double DriverZ, Textures.Texture Texture, Color32 Color, bool AddStateToLastElement) {
			// create object
			ObjectManager.StaticObject Object = new ObjectManager.StaticObject();
			Vector3[] v = new Vector3[4];
			double sx = 0.5 * WorldWidth * Width / FullWidth;
			double sy = 0.5 * WorldHeight * Height / FullHeight;
			v[0] = new Vector3(-sx, -sy, 0);
			v[1] = new Vector3(-sx, sy, 0);
			v[2] = new Vector3(sx, sy, 0);
			v[3] = new Vector3(sx, -sy, 0);
			World.Vertex t0 = new World.Vertex(v[0], new Vector2(0.0f, 1.0f));
			World.Vertex t1 = new World.Vertex(v[1], new Vector2(0.0f, 0.0f));
			World.Vertex t2 = new World.Vertex(v[2], new Vector2(1.0f, 0.0f));
			World.Vertex t3 = new World.Vertex(v[3], new Vector2(1.0f, 1.0f));
			Object.Mesh.Vertices = new World.Vertex[] { t0, t1, t2, t3 };
			Object.Mesh.Faces = new World.MeshFace[] { new World.MeshFace(new int[] { 0, 1, 2, 3 }) };
			Object.Mesh.Materials = new World.MeshMaterial[1];
			Object.Mesh.Materials[0].Flags = Texture != null ? (byte)World.MeshMaterial.TransparentColorMask : (byte)0;
			Object.Mesh.Materials[0].Color = Color;
			Object.Mesh.Materials[0].TransparentColor = new Color24(0, 0, 255);
			Object.Mesh.Materials[0].DaytimeTexture = Texture;
			Object.Mesh.Materials[0].NighttimeTexture = null;
			Object.Dynamic = true;
			// calculate offset
			Vector3 o;
			o.X = WorldLeft + sx + WorldWidth * Left / FullWidth;
			o.Y = WorldTop - sy - WorldHeight * Top / FullHeight;
			o.Z = WorldZ;
			// add object
			if (AddStateToLastElement) {
				int n = Train.Cars[Train.DriverCar].CarSections[0].Elements.Length - 1;
				int j = Train.Cars[Train.DriverCar].CarSections[0].Elements[n].States.Length;
				Array.Resize<ObjectManager.AnimatedObjectState>(ref Train.Cars[Train.DriverCar].CarSections[0].Elements[n].States, j + 1);
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n].States[j].Position = o;
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n].States[j].Object = Object;
				return n;
			} else {
				int n = Train.Cars[Train.DriverCar].CarSections[0].Elements.Length;
				Array.Resize<ObjectManager.AnimatedObject>(ref Train.Cars[Train.DriverCar].CarSections[0].Elements, n + 1);
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n] = new ObjectManager.AnimatedObject();
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n].States = new ObjectManager.AnimatedObjectState[1];
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n].States[0].Position = o;
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n].States[0].Object = Object;
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n].CurrentState = 0;
				Train.Cars[Train.DriverCar].CarSections[0].Elements[n].ObjectIndex = ObjectManager.CreateDynamicObject();
				ObjectManager.Objects[Train.Cars[Train.DriverCar].CarSections[0].Elements[n].ObjectIndex] = ObjectManager.CloneObject(Object);
				return n;
			}
		}
Пример #39
0
        private static void LoadEverythingThreaded()
        {
            string RailwayFolder = GetRailwayFolder(CurrentRouteFile);
//			if (RailwayFolder == null) {
//				Interface.AddMessage(Interface.MessageType.Critical, false, "The Railway folder could not be found. Please check your folder structure.");
//				return;
//			}
            string ObjectFolder = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object");
            string SoundFolder  = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound");

            // reset
            Game.Reset(true);
            Game.MinimalisticSimulation = true;
            // screen
            World.CameraTrackFollower          = new TrackManager.TrackFollower();
            World.CameraTrackFollower.Train    = null;
            World.CameraTrackFollower.CarIndex = -1;
            World.CameraMode = World.CameraViewMode.Interior;
            // load route
            bool IsRW = string.Equals(System.IO.Path.GetExtension(CurrentRouteFile), ".rw", StringComparison.OrdinalIgnoreCase);

            CsvRwRouteParser.ParseRoute(CurrentRouteFile, IsRW, CurrentRouteEncoding, CurrentTrainFolder, ObjectFolder, SoundFolder, false);
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Game.CalculateSeaLevelConstants();
            if (Game.BogusPretrainInstructions.Length != 0)
            {
                double t = Game.BogusPretrainInstructions[0].Time;
                double p = Game.BogusPretrainInstructions[0].TrackPosition;
                for (int i = 1; i < Game.BogusPretrainInstructions.Length; i++)
                {
                    if (Game.BogusPretrainInstructions[i].Time > t)
                    {
                        t = Game.BogusPretrainInstructions[i].Time;
                    }
                    else
                    {
                        t += 1.0;
                        Game.BogusPretrainInstructions[i].Time = t;
                    }
                    if (Game.BogusPretrainInstructions[i].TrackPosition > p)
                    {
                        p = Game.BogusPretrainInstructions[i].TrackPosition;
                    }
                    else
                    {
                        p += 1.0;
                        Game.BogusPretrainInstructions[i].TrackPosition = p;
                    }
                }
            }
            RouteProgress = 1.0;
            // initialize trains
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            TrainManager.Trains = new TrainManager.Train[Game.PrecedingTrainTimeDeltas.Length + 1 + (Game.BogusPretrainInstructions.Length != 0 ? 1 : 0)];
            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                TrainManager.Trains[k]            = new TrainManager.Train();
                TrainManager.Trains[k].TrainIndex = k;
                if (k == TrainManager.Trains.Length - 1 & Game.BogusPretrainInstructions.Length != 0)
                {
                    TrainManager.Trains[k].State = TrainManager.TrainState.Bogus;
                }
                else
                {
                    TrainManager.Trains[k].State = TrainManager.TrainState.Pending;
                }
            }
            TrainManager.PlayerTrain = TrainManager.Trains[Game.PrecedingTrainTimeDeltas.Length];
            // load trains
            double TrainProgressMaximum = 0.7 + 0.3 * (double)TrainManager.Trains.Length;

            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                if (TrainManager.Trains[k].State == TrainManager.TrainState.Bogus)
                {
                    // bogus train
                    string Folder = Program.FileSystem.GetDataFolder("Compatibility", "PreTrain");
                    TrainDatParser.ParseTrainData(Folder, System.Text.Encoding.UTF8, TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    SoundCfgParser.LoadNoSound(TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.3 / TrainProgressMaximum;
                    TrainProgressCurrentSum   += TrainProgressCurrentWeight;
                }
                else
                {
                    // real train
                    TrainProgressCurrentWeight = 0.1 / TrainProgressMaximum;
                    TrainDatParser.ParseTrainData(CurrentTrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.2 / TrainProgressMaximum;
                    SoundCfgParser.ParseSoundConfig(CurrentTrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    // door open/close speed
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer != null & TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer);
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = 0.8;
                            }
                        }
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer != null & TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer);
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = 0.8;
                            }
                        }
                        const double f = 0.015;
                        const double g = 2.75;
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency  /= TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch;
                        TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency /= TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch;

                        /*
                         * Remove the following two lines, then the pitch at which doors play
                         * takes their randomized opening and closing times into account.
                         * */
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch  = 1.0;
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch = 1.0;
                    }
                }
                for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                {
                    TrainManager.Trains[k].Cars[i].FrontAxle.Follower.Train = TrainManager.Trains[k];
                    TrainManager.Trains[k].Cars[i].RearAxle.Follower.Train  = TrainManager.Trains[k];
                    TrainManager.Trains[k].Cars[i].BeaconReceiver.Train     = TrainManager.Trains[k];
                }
                // add panel section
                if (k == TrainManager.PlayerTrain.TrainIndex)
                {
                    TrainManager.Trains[k].Cars[TrainManager.Trains[k].DriverCar].CarSections             = new TrainManager.CarSection[1];
                    TrainManager.Trains[k].Cars[TrainManager.Trains[k].DriverCar].CarSections[0].Elements = new ObjectManager.AnimatedObject[] { };
                    TrainManager.Trains[k].Cars[TrainManager.Trains[k].DriverCar].CarSections[0].Overlay  = true;
                    TrainProgressCurrentWeight = 0.7 / TrainProgressMaximum;
                    TrainManager.ParsePanelConfig(CurrentTrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                }
                // add exterior section
                if (TrainManager.Trains[k].State != TrainManager.TrainState.Bogus)
                {
                    ObjectManager.UnifiedObject[] CarObjects;
                    ExtensionsCfgParser.ParseExtensionsConfig(CurrentTrainFolder, CurrentTrainEncoding, out CarObjects, TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (CarObjects[i] == null)
                        {
                            // load default exterior object
                            string file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                            ObjectManager.StaticObject so = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false);
                            if (so == null)
                            {
                                CarObjects[i] = null;
                            }
                            else
                            {
                                double sx = TrainManager.Trains[k].Cars[i].Width;
                                double sy = TrainManager.Trains[k].Cars[i].Height;
                                double sz = TrainManager.Trains[k].Cars[i].Length;
                                CsvB3dObjectParser.ApplyScale(so, sx, sy, sz);
                                CarObjects[i] = so;
                            }
                        }
                        if (CarObjects[i] != null)
                        {
                            // add object
                            int j = TrainManager.Trains[k].Cars[i].CarSections.Length;
                            Array.Resize <TrainManager.CarSection>(ref TrainManager.Trains[k].Cars[i].CarSections, j + 1);
                            if (CarObjects[i] is ObjectManager.StaticObject)
                            {
                                ObjectManager.StaticObject s = (ObjectManager.StaticObject)CarObjects[i];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements                       = new ObjectManager.AnimatedObject[1];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0]                    = new ObjectManager.AnimatedObject();
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].States             = new ObjectManager.AnimatedObjectState[1];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].States[0].Position = new Vector3(0.0, 0.0, 0.0);
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].States[0].Object   = s;
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].CurrentState       = 0;
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].ObjectIndex        = ObjectManager.CreateDynamicObject();
                            }
                            else if (CarObjects[i] is ObjectManager.AnimatedObjectCollection)
                            {
                                ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)CarObjects[i];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements = new ObjectManager.AnimatedObject[a.Objects.Length];
                                for (int h = 0; h < a.Objects.Length; h++)
                                {
                                    TrainManager.Trains[k].Cars[i].CarSections[j].Elements[h]             = a.Objects[h];
                                    TrainManager.Trains[k].Cars[i].CarSections[j].Elements[h].ObjectIndex = ObjectManager.CreateDynamicObject();
                                }
                            }
                        }
                    }
                }
                // place cars
                {
                    double z = 0.0;
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        TrainManager.Trains[k].Cars[i].FrontAxle.Follower.TrackPosition = z - 0.5 * TrainManager.Trains[k].Cars[i].Length + TrainManager.Trains[k].Cars[i].FrontAxlePosition;
                        TrainManager.Trains[k].Cars[i].RearAxle.Follower.TrackPosition  = z - 0.5 * TrainManager.Trains[k].Cars[i].Length + TrainManager.Trains[k].Cars[i].RearAxlePosition;
                        TrainManager.Trains[k].Cars[i].BeaconReceiver.TrackPosition     = z - 0.5 * TrainManager.Trains[k].Cars[i].Length + TrainManager.Trains[k].Cars[i].BeaconReceiverPosition;
                        z -= TrainManager.Trains[k].Cars[i].Length;
                        if (i < TrainManager.Trains[k].Cars.Length - 1)
                        {
                            z -= 0.5 * (TrainManager.Trains[k].Couplers[i].MinimumDistanceBetweenCars + TrainManager.Trains[k].Couplers[i].MaximumDistanceBetweenCars);
                        }
                    }
                }
                // configure ai / timetable
                if (TrainManager.Trains[k] == TrainManager.PlayerTrain)
                {
                    TrainManager.Trains[k].TimetableDelta = 0.0;
                }
                else if (TrainManager.Trains[k].State != TrainManager.TrainState.Bogus)
                {
                    TrainManager.Trains[k].AI                  = new Game.SimpleHumanDriverAI(TrainManager.Trains[k]);
                    TrainManager.Trains[k].TimetableDelta      = Game.PrecedingTrainTimeDeltas[k];
                    TrainManager.Trains[k].Specs.DoorOpenMode  = TrainManager.DoorMode.Manual;
                    TrainManager.Trains[k].Specs.DoorCloseMode = TrainManager.DoorMode.Manual;
                }
            }
            TrainProgress = 1.0;
            // finished created objects
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            ObjectManager.FinishCreatingObjects();
            // update sections
            if (Game.Sections.Length > 0)
            {
                Game.UpdateSection(Game.Sections.Length - 1);
            }
            // load plugin
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                if (TrainManager.Trains[i].State != TrainManager.TrainState.Bogus)
                {
                    if (TrainManager.Trains[i] == TrainManager.PlayerTrain)
                    {
                        if (!PluginManager.LoadCustomPlugin(TrainManager.Trains[i], CurrentTrainFolder, CurrentTrainEncoding))
                        {
                            PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], CurrentTrainFolder);
                        }
                    }
                    else
                    {
                        PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], CurrentTrainFolder);
                    }
                }
            }
        }
Пример #40
0
        /// <summary>Jumps a train to a new station</summary>
        /// <param name="train">The train</param>
        /// <param name="stationIndex">The zero-based index of the station</param>
        internal static void JumpTrain(Train train, int stationIndex)
        {
            if (train == PlayerTrain)
            {
                for (int i = 0; i < ObjectManager.AnimatedWorldObjects.Length; i++)
                {
                    var obj = ObjectManager.AnimatedWorldObjects[i] as ObjectManager.TrackFollowingObject;
                    if (obj != null)
                    {
                        //Track followers should be reset if we jump between stations
                        obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.FrontAxlePosition;
                        obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.RearAxlePosition;
                        obj.FrontAxleFollower.UpdateWorldCoordinates(false);
                        obj.RearAxleFollower.UpdateWorldCoordinates(false);
                    }
                }
            }
            train.StationState = TrainStopState.Jumping;
            int stopIndex = Game.GetStopIndex(stationIndex, train.Cars.Length);

            if (stopIndex >= 0)
            {
                if (train == PlayerTrain)
                {
                    if (train.Plugin != null)
                    {
                        train.Plugin.BeginJump((OpenBveApi.Runtime.InitializationModes)Game.TrainStart);
                    }
                }
                for (int h = 0; h < train.Cars.Length; h++)
                {
                    train.Cars[h].Specs.CurrentSpeed = 0.0;
                }
                double d = Game.Stations[stationIndex].Stops[stopIndex].TrackPosition - train.Cars[0].FrontAxle.Follower.TrackPosition + train.Cars[0].FrontAxle.Position - 0.5 * train.Cars[0].Length;
                if (train == PlayerTrain)
                {
                    TrackManager.SuppressSoundEvents = true;
                }
                while (d != 0.0)
                {
                    double x;
                    if (Math.Abs(d) > 1.0)
                    {
                        x = (double)Math.Sign(d);
                    }
                    else
                    {
                        x = d;
                    }
                    for (int h = 0; h < train.Cars.Length; h++)
                    {
                        train.Cars[h].Move(x, 0.0);
                    }
                    if (Math.Abs(d) >= 1.0)
                    {
                        d -= x;
                    }
                    else
                    {
                        break;
                    }
                }
                if (train == PlayerTrain)
                {
                    TrainManager.UnderailTrains();
                    TrackManager.SuppressSoundEvents = false;
                }
                if (train.Handles.EmergencyBrake.Driver)
                {
                    train.ApplyNotch(0, false, 0, true);
                }
                else
                {
                    train.ApplyNotch(0, false, train.Handles.Brake.MaximumNotch, false);
                    train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                }
                if (Game.Sections.Length > 0)
                {
                    Game.UpdateSection(Game.Sections.Length - 1);
                }
                if (train == PlayerTrain)
                {
                    if (Game.CurrentScore.ArrivalStation <= stationIndex)
                    {
                        Game.CurrentScore.ArrivalStation = stationIndex + 1;
                    }
                }
                if (train == PlayerTrain)
                {
                    if (Game.Stations[stationIndex].ArrivalTime >= 0.0)
                    {
                        Game.SecondsSinceMidnight = Game.Stations[stationIndex].ArrivalTime;
                    }
                    else if (Game.Stations[stationIndex].DepartureTime >= 0.0)
                    {
                        Game.SecondsSinceMidnight = Game.Stations[stationIndex].DepartureTime - Game.Stations[stationIndex].StopTime;
                    }
                }
                for (int i = 0; i < train.Cars.Length; i++)
                {
                    train.Cars[i].Doors[0].AnticipatedOpen = Game.Stations[stationIndex].OpenLeftDoors;
                    train.Cars[i].Doors[1].AnticipatedOpen = Game.Stations[stationIndex].OpenRightDoors;
                }
                if (train == PlayerTrain)
                {
                    Game.CurrentScore.DepartureStation = stationIndex;
                    Game.CurrentInterface = Game.InterfaceType.Normal;
                    //Game.Messages = new Game.Message[] { };
                }
                ObjectManager.UpdateAnimatedWorldObjects(0.0, true);
                TrainManager.UpdateTrainObjects(0.0, true);
                if (train == PlayerTrain)
                {
                    if (train.Plugin != null)
                    {
                        train.Plugin.EndJump();
                    }
                }
                train.StationState = TrainStopState.Pending;
            }
        }
Пример #41
0
        /// <summary>Renders all default HUD elements</summary>
        /// <param name="Element">The HUD element these are to be rendererd onto</param>
        /// <param name="TimeElapsed">The time elapsed</param>
        private static void RenderHUDElement(HUD.Element Element, double TimeElapsed)
        {
            TrainManager.TrainDoorState      LeftDoors  = TrainManager.GetDoorsState(TrainManager.PlayerTrain, true, false);
            TrainManager.TrainDoorState      RightDoors = TrainManager.GetDoorsState(TrainManager.PlayerTrain, false, true);
            System.Globalization.CultureInfo Culture    = System.Globalization.CultureInfo.InvariantCulture;
            string Command = Element.Subject.ToLowerInvariant();
            // default
            double w, h;

            if (Element.CenterMiddle.BackgroundTexture != null)
            {
                if (Program.CurrentHost.LoadTexture(Element.CenterMiddle.BackgroundTexture, OpenGlTextureWrapMode.ClampClamp))
                {
                    w = (double)Element.CenterMiddle.BackgroundTexture.Width;
                    h = (double)Element.CenterMiddle.BackgroundTexture.Height;
                }
                else
                {
                    w = 0.0; h = 0.0;
                }
            }
            else
            {
                w = 0.0; h = 0.0;
            }
            double x = Element.Alignment.X < 0 ? 0.0 : Element.Alignment.X == 0 ? 0.5 * (LibRender.Screen.Width - w) : LibRender.Screen.Width - w;
            double y = Element.Alignment.Y < 0 ? 0.0 : Element.Alignment.Y == 0 ? 0.5 * (LibRender.Screen.Height - h) : LibRender.Screen.Height - h;

            x += Element.Position.X;
            y += Element.Position.Y;
            // command
            const double speed = 1.0;
            MessageColor sc    = MessageColor.None;
            string       t;

            switch (Command)
            {
            case "reverser":
                if (TrainManager.PlayerTrain.Handles.Reverser.Driver < 0)
                {
                    sc = MessageColor.Orange;
                    if (TrainManager.PlayerTrain.ReverserDescriptions != null && TrainManager.PlayerTrain.ReverserDescriptions.Length > 2)
                    {
                        t = TrainManager.PlayerTrain.ReverserDescriptions[2];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandleBackward;
                    }
                }
                else if (TrainManager.PlayerTrain.Handles.Reverser.Driver > 0)
                {
                    sc = MessageColor.Blue;
                    if (TrainManager.PlayerTrain.ReverserDescriptions != null && TrainManager.PlayerTrain.ReverserDescriptions.Length > 0)
                    {
                        t = TrainManager.PlayerTrain.ReverserDescriptions[0];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandleForward;
                    }
                }
                else
                {
                    sc = MessageColor.Gray;
                    if (TrainManager.PlayerTrain.ReverserDescriptions != null && TrainManager.PlayerTrain.ReverserDescriptions.Length > 1)
                    {
                        t = TrainManager.PlayerTrain.ReverserDescriptions[1];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandleNeutral;
                    }
                }
                Element.TransitionState = 0.0;
                break;

            case "power":
                if (TrainManager.PlayerTrain.Handles.SingleHandle)
                {
                    return;
                }
                if (TrainManager.PlayerTrain.Handles.Power.Driver == 0)
                {
                    sc = MessageColor.Gray;
                    if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.PowerNotchDescriptions.Length > 0)
                    {
                        t = TrainManager.PlayerTrain.PowerNotchDescriptions[0];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandlePowerNull;
                    }
                }
                else
                {
                    sc = MessageColor.Blue;
                    if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.Handles.Power.Driver < TrainManager.PlayerTrain.PowerNotchDescriptions.Length)
                    {
                        t = TrainManager.PlayerTrain.PowerNotchDescriptions[TrainManager.PlayerTrain.Handles.Power.Driver];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandlePower + TrainManager.PlayerTrain.Handles.Power.Driver.ToString(Culture);
                    }
                }
                Element.TransitionState = 0.0;
                break;

            case "brake":
                if (TrainManager.PlayerTrain.Handles.SingleHandle)
                {
                    return;
                }
                if (TrainManager.PlayerTrain.Handles.Brake is TrainManager.AirBrakeHandle)
                {
                    if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver)
                    {
                        sc = MessageColor.Red;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 0)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[0];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleEmergency;
                        }
                    }
                    else if (TrainManager.PlayerTrain.Handles.Brake.Driver == (int)TrainManager.AirBrakeHandleState.Release)
                    {
                        sc = MessageColor.Gray;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleRelease;
                        }
                    }
                    else if (TrainManager.PlayerTrain.Handles.Brake.Driver == (int)TrainManager.AirBrakeHandleState.Lap)
                    {
                        sc = MessageColor.Blue;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 2)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[2];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleLap;
                        }
                    }
                    else
                    {
                        sc = MessageColor.Orange;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 3)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[3];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleService;
                        }
                    }
                }
                else
                {
                    if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver)
                    {
                        sc = MessageColor.Red;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 0)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[0];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleEmergency;
                        }
                    }
                    else if (TrainManager.PlayerTrain.Handles.HoldBrake.Driver)
                    {
                        sc = MessageColor.Green;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 2)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[2];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleHoldBrake;
                        }
                    }
                    else if (TrainManager.PlayerTrain.Handles.Brake.Driver == 0)
                    {
                        sc = MessageColor.Gray;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleBrakeNull;
                        }
                    }
                    else
                    {
                        sc = MessageColor.Orange;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && ((TrainManager.PlayerTrain.Handles.HasHoldBrake && TrainManager.PlayerTrain.Handles.Brake.Driver + 2 < TrainManager.PlayerTrain.BrakeNotchDescriptions.Length) || (!TrainManager.PlayerTrain.Handles.HasHoldBrake && TrainManager.PlayerTrain.Handles.Brake.Driver + 1 < TrainManager.PlayerTrain.BrakeNotchDescriptions.Length)))
                        {
                            t = TrainManager.PlayerTrain.Handles.HasHoldBrake ? TrainManager.PlayerTrain.BrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.Brake.Driver + 2] : TrainManager.PlayerTrain.BrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.Brake.Driver + 1];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleBrake + TrainManager.PlayerTrain.Handles.Brake.Driver.ToString(Culture);
                        }
                    }
                }
                Element.TransitionState = 0.0;
                break;

            case "locobrake":
                if (!TrainManager.PlayerTrain.Handles.HasLocoBrake)
                {
                    return;
                }

                if (TrainManager.PlayerTrain.Handles.LocoBrake is TrainManager.LocoAirBrakeHandle)
                {
                    if (TrainManager.PlayerTrain.Handles.LocoBrake.Driver == (int)TrainManager.AirBrakeHandleState.Release)
                    {
                        sc = MessageColor.Gray;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleRelease;
                        }
                    }
                    else if (TrainManager.PlayerTrain.Handles.LocoBrake.Driver == (int)TrainManager.AirBrakeHandleState.Lap)
                    {
                        sc = MessageColor.Blue;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 2)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[2];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleLap;
                        }
                    }
                    else
                    {
                        sc = MessageColor.Orange;
                        if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 3)
                        {
                            t = TrainManager.PlayerTrain.BrakeNotchDescriptions[3];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleService;
                        }
                    }
                }
                else
                {
                    if (TrainManager.PlayerTrain.Handles.LocoBrake.Driver == 0)
                    {
                        sc = MessageColor.Gray;
                        if (TrainManager.PlayerTrain.LocoBrakeNotchDescriptions != null && TrainManager.PlayerTrain.LocoBrakeNotchDescriptions.Length > 1)
                        {
                            t = TrainManager.PlayerTrain.LocoBrakeNotchDescriptions[1];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleBrakeNull;
                        }
                    }
                    else
                    {
                        sc = MessageColor.Orange;
                        if (TrainManager.PlayerTrain.LocoBrakeNotchDescriptions != null && TrainManager.PlayerTrain.Handles.LocoBrake.Driver < TrainManager.PlayerTrain.LocoBrakeNotchDescriptions.Length)
                        {
                            t = TrainManager.PlayerTrain.LocoBrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.LocoBrake.Driver];
                        }
                        else
                        {
                            t = Translations.QuickReferences.HandleLocoBrake + TrainManager.PlayerTrain.Handles.LocoBrake.Driver.ToString(Culture);
                        }
                    }
                }
                Element.TransitionState = 0.0;
                break;

            case "single":
                if (!TrainManager.PlayerTrain.Handles.SingleHandle)
                {
                    return;
                }
                if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver)
                {
                    sc = MessageColor.Red;
                    if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 0)
                    {
                        t = TrainManager.PlayerTrain.BrakeNotchDescriptions[0];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandleEmergency;
                    }
                }
                else if (TrainManager.PlayerTrain.Handles.HoldBrake.Driver)
                {
                    sc = MessageColor.Green;
                    if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1)
                    {
                        t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandleHoldBrake;
                    }
                }
                else if (TrainManager.PlayerTrain.Handles.Brake.Driver > 0)
                {
                    sc = MessageColor.Orange;
                    if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.Handles.Brake.Driver + 3 < TrainManager.PlayerTrain.BrakeNotchDescriptions.Length)
                    {
                        t = TrainManager.PlayerTrain.BrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.Brake.Driver + 3];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandleBrake + TrainManager.PlayerTrain.Handles.Brake.Driver.ToString(Culture);
                    }
                }
                else if (TrainManager.PlayerTrain.Handles.Power.Driver > 0)
                {
                    sc = MessageColor.Blue;
                    if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.Handles.Power.Driver < TrainManager.PlayerTrain.PowerNotchDescriptions.Length)
                    {
                        t = TrainManager.PlayerTrain.PowerNotchDescriptions[TrainManager.PlayerTrain.Handles.Power.Driver];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandlePower + TrainManager.PlayerTrain.Handles.Power.Driver.ToString(Culture);
                    }
                }
                else
                {
                    sc = MessageColor.Gray;
                    if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.PowerNotchDescriptions.Length > 0)
                    {
                        t = TrainManager.PlayerTrain.PowerNotchDescriptions[0];
                    }
                    else
                    {
                        t = Translations.QuickReferences.HandlePowerNull;
                    }
                }
                Element.TransitionState = 0.0;
                break;

            case "doorsleft":
            case "doorsright":
            {
                if ((LeftDoors & TrainManager.TrainDoorState.AllClosed) == 0 | (RightDoors & TrainManager.TrainDoorState.AllClosed) == 0)
                {
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else
                {
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                }
                TrainManager.TrainDoorState Doors = Command == "doorsleft" ? LeftDoors : RightDoors;
                if ((Doors & TrainManager.TrainDoorState.Mixed) != 0)
                {
                    sc = MessageColor.Orange;
                }
                else if ((Doors & TrainManager.TrainDoorState.AllClosed) != 0)
                {
                    sc = MessageColor.Gray;
                }
                else if (TrainManager.PlayerTrain.Specs.DoorCloseMode == TrainManager.DoorMode.Manual)
                {
                    sc = MessageColor.Green;
                }
                else
                {
                    sc = MessageColor.Blue;
                }
                t = Command == "doorsleft" ? Translations.QuickReferences.DoorsLeft : Translations.QuickReferences.DoorsRight;
            } break;

            case "stopleft":
            case "stopright":
            case "stopnone":
            {
                int s = TrainManager.PlayerTrain.Station;
                if (s >= 0 && CurrentRoute.Stations[s].PlayerStops() && Interface.CurrentOptions.GameMode != GameMode.Expert)
                {
                    bool cond;
                    if (Command == "stopleft")
                    {
                        cond = CurrentRoute.Stations[s].OpenLeftDoors;
                    }
                    else if (Command == "stopright")
                    {
                        cond = CurrentRoute.Stations[s].OpenRightDoors;
                    }
                    else
                    {
                        cond = !CurrentRoute.Stations[s].OpenLeftDoors & !CurrentRoute.Stations[s].OpenRightDoors;
                    }
                    if (TrainManager.PlayerTrain.StationState == TrainStopState.Pending & cond)
                    {
                        Element.TransitionState -= speed * TimeElapsed;
                        if (Element.TransitionState < 0.0)
                        {
                            Element.TransitionState = 0.0;
                        }
                    }
                    else
                    {
                        Element.TransitionState += speed * TimeElapsed;
                        if (Element.TransitionState > 1.0)
                        {
                            Element.TransitionState = 1.0;
                        }
                    }
                }
                else
                {
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                }
                t = Element.Text;
            } break;

            case "stoplefttick":
            case "stoprighttick":
            case "stopnonetick":
            {
                int s = TrainManager.PlayerTrain.Station;
                if (s >= 0 && CurrentRoute.Stations[s].PlayerStops() && Interface.CurrentOptions.GameMode != GameMode.Expert)
                {
                    int c = CurrentRoute.Stations[s].GetStopIndex(TrainManager.PlayerTrain.Cars.Length);
                    if (c >= 0)
                    {
                        bool cond;
                        if (Command == "stoplefttick")
                        {
                            cond = CurrentRoute.Stations[s].OpenLeftDoors;
                        }
                        else if (Command == "stoprighttick")
                        {
                            cond = CurrentRoute.Stations[s].OpenRightDoors;
                        }
                        else
                        {
                            cond = !CurrentRoute.Stations[s].OpenLeftDoors & !CurrentRoute.Stations[s].OpenRightDoors;
                        }
                        if (TrainManager.PlayerTrain.StationState == TrainStopState.Pending & cond)
                        {
                            Element.TransitionState -= speed * TimeElapsed;
                            if (Element.TransitionState < 0.0)
                            {
                                Element.TransitionState = 0.0;
                            }
                        }
                        else
                        {
                            Element.TransitionState += speed * TimeElapsed;
                            if (Element.TransitionState > 1.0)
                            {
                                Element.TransitionState = 1.0;
                            }
                        }
                        double d = TrainManager.PlayerTrain.StationDistanceToStopPoint;
                        double r;
                        if (d > 0.0)
                        {
                            r = d / CurrentRoute.Stations[s].Stops[c].BackwardTolerance;
                        }
                        else
                        {
                            r = d / CurrentRoute.Stations[s].Stops[c].ForwardTolerance;
                        }
                        if (r < -1.0)
                        {
                            r = -1.0;
                        }
                        if (r > 1.0)
                        {
                            r = 1.0;
                        }
                        y -= r * (double)Element.Value1;
                    }
                    else
                    {
                        Element.TransitionState += speed * TimeElapsed;
                        if (Element.TransitionState > 1.0)
                        {
                            Element.TransitionState = 1.0;
                        }
                    }
                }
                else
                {
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                }
                t = Element.Text;
            } break;

            case "clock":
            {
                int hours   = (int)Math.Floor(Game.SecondsSinceMidnight);
                int seconds = hours % 60; hours /= 60;
                int minutes = hours % 60; hours /= 60;
                hours %= 24;
                t      = hours.ToString(Culture).PadLeft(2, '0') + ":" + minutes.ToString(Culture).PadLeft(2, '0') + ":" + seconds.ToString(Culture).PadLeft(2, '0');
                if (OptionClock)
                {
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else
                {
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                }
            } break;

            case "gradient":
                if (OptionGradient == GradientDisplayMode.Percentage)
                {
                    if (World.CameraTrackFollower.Pitch != 0)
                    {
                        double pc = World.CameraTrackFollower.Pitch;
                        t = Math.Abs(pc).ToString("0.00", Culture) + "%" + (Math.Abs(pc) == pc ? " ↗" : " ↘");
                    }
                    else
                    {
                        t = "Level";
                    }
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else if (OptionGradient == GradientDisplayMode.UnitOfChange)
                {
                    if (World.CameraTrackFollower.Pitch != 0)
                    {
                        double gr = 1000 / World.CameraTrackFollower.Pitch;
                        t = "1 in " + Math.Abs(gr).ToString("0", Culture) + (Math.Abs(gr) == gr ? " ↗" : " ↘");
                    }
                    else
                    {
                        t = "Level";
                    }
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else if (OptionGradient == GradientDisplayMode.Permil)
                {
                    if (World.CameraTrackFollower.Pitch != 0)
                    {
                        double pm = World.CameraTrackFollower.Pitch;
                        t = Math.Abs(pm).ToString("0.00", Culture) + "‰" + (Math.Abs(pm) == pm ? " ↗" : " ↘");
                    }
                    else
                    {
                        t = "Level";
                    }
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else
                {
                    if (World.CameraTrackFollower.Pitch != 0)
                    {
                        double gr = 1000 / World.CameraTrackFollower.Pitch;
                        t = "1 in " + Math.Abs(gr).ToString("0", Culture) + (Math.Abs(gr) == gr ? " ↗" : " ↘");
                    }
                    else
                    {
                        t = "Level";
                    }
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                } break;

            case "speed":
                if (OptionSpeed == SpeedDisplayMode.Kmph)
                {
                    double kmph = Math.Abs(TrainManager.PlayerTrain.CurrentSpeed) * 3.6;
                    t = kmph.ToString("0.00", Culture) + " km/h";
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else if (OptionSpeed == SpeedDisplayMode.Mph)
                {
                    double mph = Math.Abs(TrainManager.PlayerTrain.CurrentSpeed) * 2.2369362920544;
                    t = mph.ToString("0.00", Culture) + " mph";
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else
                {
                    double mph = Math.Abs(TrainManager.PlayerTrain.CurrentSpeed) * 2.2369362920544;
                    t = mph.ToString("0.00", Culture) + " mph";
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                } break;

            case "dist_next_station":
                int i;
                if (TrainManager.PlayerTrain.Station >= 0 && TrainManager.PlayerTrain.StationState != TrainStopState.Completed)
                {
                    i = TrainManager.PlayerTrain.LastStation;
                }
                else
                {
                    i = TrainManager.PlayerTrain.LastStation + 1;
                }
                if (i > CurrentRoute.Stations.Length - 1)
                {
                    i = TrainManager.PlayerTrain.LastStation;
                }
                int    n  = CurrentRoute.Stations[i].GetStopIndex(TrainManager.PlayerTrain.NumberOfCars);
                double p0 = TrainManager.PlayerTrain.FrontCarTrackPosition();
                double p1;
                if (CurrentRoute.Stations[i].Stops.Length > 0)
                {
                    p1 = CurrentRoute.Stations[i].Stops[n].TrackPosition;
                }
                else
                {
                    p1 = CurrentRoute.Stations[i].DefaultTrackPosition;
                }
                double m = p1 - p0;
                if (OptionDistanceToNextStation == DistanceToNextStationDisplayMode.Km)
                {
                    if (CurrentRoute.Stations[i].PlayerStops())
                    {
                        t = "Stop: ";
                        if (Math.Abs(m) <= 10.0)
                        {
                            t += m.ToString("0.00", Culture) + " m";
                        }
                        else
                        {
                            m /= 1000.0;
                            t += m.ToString("0.000", Culture) + " km";
                        }
                    }
                    else
                    {
                        m /= 1000.0;
                        t  = "Pass: "******"0.000", Culture) + " km";
                    }
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else if (OptionDistanceToNextStation == DistanceToNextStationDisplayMode.Mile)
                {
                    m /= 1609.34;
                    if (CurrentRoute.Stations[i].PlayerStops())
                    {
                        t = "Stop: ";
                    }
                    else
                    {
                        t = "Pass: "******"0.0000", Culture) + " miles";
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else
                {
                    m /= 1609.34;
                    if (CurrentRoute.Stations[i].PlayerStops())
                    {
                        t = "Stop: ";
                    }
                    else
                    {
                        t = "Pass: "******"0.0000", Culture) + " miles";
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                } break;

            case "fps":
                int fps = (int)Math.Round(LibRender.Renderer.FrameRate);
                t = fps.ToString(Culture) + " fps";
                if (OptionFrameRates)
                {
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else
                {
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                } break;

            case "ai":
                t = "A.I.";
                if (TrainManager.PlayerTrain.AI != null)
                {
                    Element.TransitionState -= speed * TimeElapsed;
                    if (Element.TransitionState < 0.0)
                    {
                        Element.TransitionState = 0.0;
                    }
                }
                else
                {
                    Element.TransitionState += speed * TimeElapsed;
                    if (Element.TransitionState > 1.0)
                    {
                        Element.TransitionState = 1.0;
                    }
                } break;

            case "score":
                if (Interface.CurrentOptions.GameMode == GameMode.Arcade)
                {
                    t = Game.CurrentScore.CurrentValue.ToString(Culture) + " / " + Game.CurrentScore.Maximum.ToString(Culture);
                    if (Game.CurrentScore.CurrentValue < 0)
                    {
                        sc = MessageColor.Red;
                    }
                    else if (Game.CurrentScore.CurrentValue > 0)
                    {
                        sc = MessageColor.Green;
                    }
                    else
                    {
                        sc = MessageColor.Gray;
                    }
                    Element.TransitionState = 0.0;
                }
                else
                {
                    Element.TransitionState = 1.0;
                    t = "";
                } break;

            default:
                t = Element.Text;
                break;
            }
            // transitions
            float alpha = 1.0f;

            if ((Element.Transition & HUD.Transition.Move) != 0)
            {
                double s = Element.TransitionState;
                x += Element.TransitionVector.X * s * s;
                y += Element.TransitionVector.Y * s * s;
            }
            if ((Element.Transition & HUD.Transition.Fade) != 0)
            {
                alpha = (float)(1.0 - Element.TransitionState);
            }
            else if (Element.Transition == HUD.Transition.None)
            {
                alpha = (float)(1.0 - Element.TransitionState);
            }
            // render
            if (alpha != 0.0f)
            {
                // background
                if (Element.Subject == "reverser")
                {
                    w = Math.Max(w, TrainManager.PlayerTrain.MaxReverserWidth);
                    //X-Pos doesn't need to be changed
                }
                if (Element.Subject == "power")
                {
                    w = Math.Max(w, TrainManager.PlayerTrain.MaxPowerNotchWidth);
                    if (TrainManager.PlayerTrain.MaxReverserWidth > 48)
                    {
                        x += (TrainManager.PlayerTrain.MaxReverserWidth - 48);
                    }
                }
                if (Element.Subject == "brake")
                {
                    w = Math.Max(w, TrainManager.PlayerTrain.MaxBrakeNotchWidth);
                    if (TrainManager.PlayerTrain.MaxReverserWidth > 48)
                    {
                        x += (TrainManager.PlayerTrain.MaxReverserWidth - 48);
                    }
                    if (TrainManager.PlayerTrain.MaxPowerNotchWidth > 48)
                    {
                        x += (TrainManager.PlayerTrain.MaxPowerNotchWidth - 48);
                    }
                }
                if (Element.Subject == "single")
                {
                    w = Math.Max(Math.Max(w, TrainManager.PlayerTrain.MaxPowerNotchWidth), TrainManager.PlayerTrain.MaxBrakeNotchWidth);
                    if (TrainManager.PlayerTrain.MaxReverserWidth > 48)
                    {
                        x += (TrainManager.PlayerTrain.MaxReverserWidth - 48);
                    }
                }
                if (Element.CenterMiddle.BackgroundTexture != null)
                {
                    if (Program.CurrentHost.LoadTexture(Element.CenterMiddle.BackgroundTexture, OpenGlTextureWrapMode.ClampClamp))
                    {
                        Color128 c = Element.BackgroundColor.CreateBackColor(sc, alpha);
                        GL.Color4(c.R, c.G, c.B, c.A);
                        LibRender.Renderer.RenderOverlayTexture(Element.CenterMiddle.BackgroundTexture, x, y, x + w, y + h);
                    }
                }
                {                 // text
                    System.Drawing.Size size = Element.Font.MeasureString(t);
                    float  u = size.Width;
                    float  v = size.Height;
                    double p = Math.Round(Element.TextAlignment.X < 0 ? x : Element.TextAlignment.X == 0 ? x + 0.5 * (w - u) : x + w - u);
                    double q = Math.Round(Element.TextAlignment.Y < 0 ? y : Element.TextAlignment.Y == 0 ? y + 0.5 * (h - v) : y + h - v);
                    p += Element.TextPosition.X;
                    q += Element.TextPosition.Y;
                    Color128 c = Element.TextColor.CreateTextColor(sc, alpha);
                    LibRender.Renderer.DrawString(Element.Font, t, new System.Drawing.Point((int)p, (int)q), TextAlignment.TopLeft, c, Element.TextShadow);
                }
                // overlay
                if (Element.CenterMiddle.OverlayTexture != null)
                {
                    if (Program.CurrentHost.LoadTexture(Element.CenterMiddle.OverlayTexture, OpenGlTextureWrapMode.ClampClamp))
                    {
                        Color128 c = Element.OverlayColor.CreateBackColor(sc, alpha);
                        GL.Color4(c.R, c.G, c.B, c.A);
                        LibRender.Renderer.RenderOverlayTexture(Element.CenterMiddle.OverlayTexture, x, y, x + w, y + h);
                    }
                }
            }
        }
Пример #42
0
 // update
 internal static void Update(double TimeElapsed)
 {
     if (OpenAlContext != ContextHandle.Zero)
     {
         // listener
         double vx = World.CameraTrackFollower.WorldDirection.X * World.CameraSpeed;
         double vy = World.CameraTrackFollower.WorldDirection.Y * World.CameraSpeed;
         double vz = World.CameraTrackFollower.WorldDirection.Z * World.CameraSpeed;
         if (World.CameraMode == World.CameraViewMode.Interior | World.CameraMode == World.CameraViewMode.InteriorLookAhead)
         {
             ListenerVelocity[0] = 0.0f;
             ListenerVelocity[1] = 0.0f;
             ListenerVelocity[2] = 0.0f;
         }
         else
         {
             ListenerVelocity[0] = (float)vx;
             ListenerVelocity[1] = (float)vy;
             ListenerVelocity[2] = (float)vz;
         }
         ListenerOrientation[0] = (float)World.AbsoluteCameraDirection.X;
         ListenerOrientation[1] = (float)World.AbsoluteCameraDirection.Y;
         ListenerOrientation[2] = (float)World.AbsoluteCameraDirection.Z;
         ListenerOrientation[3] = (float)-World.AbsoluteCameraUp.X;
         ListenerOrientation[4] = (float)-World.AbsoluteCameraUp.Y;
         ListenerOrientation[5] = (float)-World.AbsoluteCameraUp.Z;
         AL.Listener(ALListener3f.Position, ListenerPosition[0], ListenerPosition[1], ListenerPosition[2]);
         AL.Listener(ALListener3f.Velocity, ListenerVelocity[0], ListenerVelocity[1], ListenerVelocity[2]);
         AL.Listener(ALListenerfv.Orientation, ref ListenerOrientation);
         double cx = World.AbsoluteCameraPosition.X;
         double cy = World.AbsoluteCameraPosition.Y;
         double cz = World.AbsoluteCameraPosition.Z;
         if (Mute)
         {
             // mute
             for (int i = 0; i < SoundSources.Length; i++)
             {
                 if (SoundSources[i] != null && !SoundSources[i].FinishedPlaying)
                 {
                     if (!SoundSources[i].Suppressed)
                     {
                         if (SoundSources[i].Looped)
                         {
                             if (SoundSources[i].OpenAlSourceIndex.Valid)
                             {
                                 int j = SoundSources[i].OpenAlSourceIndex.Index;
                                 AL.SourceStop(j);
                                 AL.DeleteSources(1, ref j);
                             }
                             SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(0, false);
                             SoundSources[i].Suppressed        = true;
                         }
                         else
                         {
                             StopSound(i, false);
                         }
                     }
                     else if (!SoundSources[i].Looped)
                     {
                         StopSound(i, false);
                     }
                 }
             }
         }
         else
         {
             // outer radius
             int n = Interface.CurrentOptions.SoundNumber - 3;
             if (SoundsActuallyPlaying >= n)
             {
                 OuterRadiusSpeed -= OuterRadiusDeceleration * TimeElapsed;
                 if (OuterRadiusSpeed < -1.0)
                 {
                     OuterRadiusSpeed = -1.0;
                 }
             }
             else if (SoundsQueriedPlaying < n)
             {
                 OuterRadiusSpeed += OuterRadiusAcceleration * TimeElapsed;
                 if (OuterRadiusSpeed > 1.0)
                 {
                     OuterRadiusSpeed = 1.0;
                 }
             }
             else
             {
                 OuterRadiusSpeed -= (double)Math.Sign(OuterRadiusSpeed) * OuterRadiusDeceleration * TimeElapsed;
                 if (OuterRadiusSpeed * OuterRadiusSpeed <= TimeElapsed * TimeElapsed)
                 {
                     OuterRadiusSpeed = 0.0;
                 }
             }
             OuterRadiusFactor += OuterRadiusSpeed * TimeElapsed;
             if (OuterRadiusFactor < OuterRadiusFactorMinimum)
             {
                 OuterRadiusFactor = OuterRadiusFactorMinimum;
             }
             else if (OuterRadiusFactor > OuterRadiusFactorMaximum)
             {
                 OuterRadiusFactor = OuterRadiusFactorMaximum;
             }
             // sources
             SoundsQueriedPlaying  = 0;
             SoundsActuallyPlaying = 0;
             for (int i = 0; i < SoundSources.Length; i++)
             {
                 if (SoundSources[i] != null && !SoundSources[i].FinishedPlaying)
                 {
                     double rx = SoundSources[i].Position.X;
                     double ry = SoundSources[i].Position.Y;
                     double rz = SoundSources[i].Position.Z;
                     double px, py, pz;
                     if (SoundSources[i].Train != null)
                     {
                         int    c = SoundSources[i].CarIndex;
                         double tx, ty, tz;
                         TrainManager.CreateWorldCoordinates(SoundSources[i].Train, c, rx, ry, rz, out px, out py, out pz, out tx, out ty, out tz);
                         px -= cx; py -= cy; pz -= cz;
                         double sp = SoundSources[i].Train.Specs.CurrentAverageSpeed;
                         if (World.CameraMode != World.CameraViewMode.Interior & World.CameraMode != World.CameraViewMode.InteriorLookAhead)
                         {
                             SoundSources[i].OpenAlVelocity[0] = (float)(tx * sp);
                             SoundSources[i].OpenAlVelocity[1] = (float)(ty * sp);
                             SoundSources[i].OpenAlVelocity[2] = (float)(tz * sp);
                         }
                         else
                         {
                             SoundSources[i].OpenAlVelocity[0] = (float)(tx * sp - vx);
                             SoundSources[i].OpenAlVelocity[1] = (float)(ty * sp - vy);
                             SoundSources[i].OpenAlVelocity[2] = (float)(tz * sp - vz);
                         }
                     }
                     else
                     {
                         px = rx - cx; py = ry - cy; pz = rz - cz;
                         if (World.CameraMode != World.CameraViewMode.Interior & World.CameraMode != World.CameraViewMode.InteriorLookAhead)
                         {
                             SoundSources[i].OpenAlVelocity[0] = 0.0f;
                             SoundSources[i].OpenAlVelocity[1] = 0.0f;
                             SoundSources[i].OpenAlVelocity[2] = 0.0f;
                         }
                         else
                         {
                             SoundSources[i].OpenAlVelocity[0] = (float)-vx;
                             SoundSources[i].OpenAlVelocity[1] = (float)-vy;
                             SoundSources[i].OpenAlVelocity[2] = (float)-vz;
                         }
                     }
                     // play the sound only if within the outer radius
                     double distanceSquared    = px * px + py * py + pz * pz;
                     double distance           = Math.Sqrt(distanceSquared);
                     double innerRadius        = SoundSources[i].Radius;
                     double outerRadius        = OuterRadiusFactor * innerRadius;
                     double outerRadiusSquared = outerRadius * outerRadius;
                     if (distanceSquared < outerRadiusSquared)
                     {
                         // sound is in range
                         double       gain;
                         double       innerRadiusSquared = innerRadius * innerRadius;
                         const double rollOffFactor      = 0.9;
                         if (distanceSquared < innerRadiusSquared)
                         {
                             gain = 1.0 - (1.0 - rollOffFactor) * distanceSquared / innerRadiusSquared;
                         }
                         else
                         {
                             double value = distance / outerRadius;
                             gain = innerRadius * rollOffFactor * (1.0 - value * value * value) / distance;
                         }
                         SoundsQueriedPlaying++;
                         SoundsActuallyPlaying++;
                         bool startPlaying = false;
                         // play sound if currently suppressed
                         if (SoundSources[i].Suppressed)
                         {
                             if (SoundSources[i].SoundBufferIndex >= 0)
                             {
                                 UseSoundBuffer(SoundSources[i].SoundBufferIndex);
                                 if (SoundBuffers[SoundSources[i].SoundBufferIndex].OpenAlBufferIndex.Valid)
                                 {
                                     int j;
                                     AL.GetError();
                                     AL.GenSources(1, out j);
                                     ALError err = AL.GetError();
                                     if (err == ALError.NoError)
                                     {
                                         SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(j, true);
                                         AL.Source(j, ALSourcei.Buffer, SoundBuffers[SoundSources[i].SoundBufferIndex].OpenAlBufferIndex.Index);
                                         SoundSources[i].Suppressed = false;
                                         startPlaying = true;
                                     }
                                     else
                                     {
                                         continue;
                                     }
                                 }
                                 else
                                 {
                                     StopSound(i, false);
                                     continue;
                                 }
                             }
                             else
                             {
                                 StopSound(i, false);
                                 continue;
                             }
                         }
                         // play or stop sound
                         if (startPlaying || IsPlaying(i))
                         {
                             SoundSources[i].OpenAlPosition[0] = (float)px;
                             SoundSources[i].OpenAlPosition[1] = (float)py;
                             SoundSources[i].OpenAlPosition[2] = (float)pz;
                             if (!SoundSources[i].OpenAlSourceIndex.Valid)
                             {
                                 throw new InvalidOperationException("A bug in the sound manager. (9431)");
                             }
                             int j = SoundSources[i].OpenAlSourceIndex.Index;
                             AL.Source(j, ALSource3f.Position, SoundSources[i].OpenAlPosition[0], SoundSources[i].OpenAlPosition[1], SoundSources[i].OpenAlPosition[2]);
                             AL.Source(j, ALSource3f.Velocity, SoundSources[i].OpenAlVelocity[0], SoundSources[i].OpenAlVelocity[1], SoundSources[i].OpenAlVelocity[2]);
                             AL.Source(j, ALSourcef.Pitch, SoundSources[i].Pitch);
                             float g = SoundSources[i].Gain * SoundSources[i].Gain * (float)gain;
                             if (g > 1.0f)
                             {
                                 g = 1.0f;
                             }
                             AL.Source(j, ALSourcef.Gain, g);
                         }
                         else
                         {
                             StopSound(i, false);
                             continue;
                         }
                         // update position and velocity of sound
                         if (startPlaying)
                         {
                             if (!SoundSources[i].OpenAlSourceIndex.Valid)
                             {
                                 throw new InvalidOperationException("A bug in the sound manager. (7625)");
                             }
                             int j = SoundSources[i].OpenAlSourceIndex.Index;
                             AL.Source(j, ALSourceb.Looping, SoundSources[i].Looped);
                             AL.Source(j, ALSourcef.ReferenceDistance, SoundBuffers[SoundSources[i].SoundBufferIndex].Radius);
                             AL.SourcePlay(j);
                         }
                     }
                     else
                     {
                         // sound is not in range
                         if (!SoundSources[i].Suppressed)
                         {
                             if (SoundSources[i].Looped)
                             {
                                 if (SoundSources[i].OpenAlSourceIndex.Valid)
                                 {
                                     int j = SoundSources[i].OpenAlSourceIndex.Index;
                                     AL.SourceStop(j);
                                     AL.DeleteSources(1, ref j);
                                 }
                                 SoundSources[i].OpenAlSourceIndex = new OpenAlIndex(0, false);
                                 SoundSources[i].Suppressed        = true;
                             }
                             else
                             {
                                 StopSound(i, false);
                             }
                         }
                         else if (!SoundSources[i].Looped)
                         {
                             StopSound(i, false);
                         }
                     }
                 }
             }
         }
         // infrequent updates
         InternalTimer += TimeElapsed;
         if (InternalTimer > 1.0)
         {
             InternalTimer = 0.0;
             double Elevation      = World.AbsoluteCameraPosition.Y + Game.RouteInitialElevation;
             double AirTemperature = Game.GetAirTemperature(Elevation);
             double AirPressure    = Game.GetAirPressure(Elevation, AirTemperature);
             double SpeedOfSound   = Game.GetSpeedOfSound(AirPressure, AirTemperature);
             AL.SpeedOfSound((float)SpeedOfSound);
         }
     }
 }
Пример #43
0
        //This renders the frame
        protected override void OnRenderFrame(FrameEventArgs e)
        {
            if (!firstFrame)
            {
                //If the load is not complete, then we shouldn't be running the mainloop
                return;
            }
            double TimeElapsed     = RenderTimeElapsed;
            double RealTimeElapsed = RenderRealTimeElapsed;

            //Next, check if we're in paused/ in a menu
            if (Game.CurrentInterface != Game.InterfaceType.Normal)
            {
                MainLoop.UpdateControlRepeats(0.0);
                MainLoop.ProcessKeyboard();
                MainLoop.ProcessControls(0.0);
                if (Game.CurrentInterface == Game.InterfaceType.Pause)
                {
                    System.Threading.Thread.Sleep(10);
                }
                //Renderer.UpdateLighting();
                Renderer.RenderScene(TimeElapsed);
                Program.currentGameWindow.SwapBuffers();
                if (MainLoop.Quit)
                {
                    Close();
                }
                //If the menu state has not changed, don't update the rendered simulation
                return;
            }

            //Use the OpenTK framerate as this is much more accurate
            //Also avoids running a calculation
            if (TotalTimeElapsedForInfo >= 0.2)
            {
                Game.InfoFrameRate      = RenderFrequency;
                TotalTimeElapsedForInfo = 0.0;
            }


            if (Game.PreviousInterface != Game.InterfaceType.Normal)
            {
                ObjectManager.UpdateAnimatedWorldObjects(0.0, false);
                Game.PreviousInterface = Game.InterfaceType.Normal;
            }
            else
            {
                ObjectManager.UpdateAnimatedWorldObjects(TimeElapsed, false);
            }

            //We need to update the camera position in the render sequence
            //Not doing this means that the camera doesn't move
            // update in one piece
            if (World.CameraMode == World.CameraViewMode.Interior | World.CameraMode == World.CameraViewMode.InteriorLookAhead)
            {
                //Update the in-car camera based upon the current driver car (Cabview or passenger view)
                TrainManager.PlayerTrain.Cars[World.CameraCar].UpdateCamera();
            }
            else if (World.CameraMode == World.CameraViewMode.Exterior)
            {
                //Update the camera position based upon the relative car position
                TrainManager.PlayerTrain.Cars[World.CameraCar].UpdateCamera();
            }
            if (World.CameraRestriction == World.CameraRestrictionMode.NotAvailable)
            {
                World.UpdateDriverBody(TimeElapsed);
            }
            //Check if we are running at an accelerated time factor-
            //Camera motion speed should be the same whatever the game speed is
            if (TimeFactor != 1)
            {
                World.UpdateAbsoluteCamera(TimeElapsed / TimeFactor);
            }
            else
            {
                World.UpdateAbsoluteCamera(TimeElapsed);
            }
            TrainManager.UpdateTrainObjects(TimeElapsed, false);
            if (World.CameraMode == World.CameraViewMode.Interior | World.CameraMode == World.CameraViewMode.InteriorLookAhead | World.CameraMode == World.CameraViewMode.Exterior)
            {
                ObjectManager.UpdateVisibility(World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z);
                int d = TrainManager.PlayerTrain.DriverCar;
                World.CameraSpeed = TrainManager.PlayerTrain.Cars[d].Specs.CurrentSpeed;
            }
            else
            {
                World.CameraSpeed = 0.0;
            }

            World.CameraAlignmentDirection = new World.CameraAlignment();
            if (MainLoop.Quit)
            {
                Program.currentGameWindow.Exit();
            }
            Renderer.UpdateLighting();
            Renderer.RenderScene(TimeElapsed);
            Sounds.Update(TimeElapsed, Interface.CurrentOptions.SoundModel);
            Program.currentGameWindow.SwapBuffers();
            Game.UpdateBlackBox();
            // pause/menu

            // limit framerate
            if (MainLoop.LimitFramerate)
            {
                System.Threading.Thread.Sleep(10);
            }
            MainLoop.UpdateControlRepeats(RealTimeElapsed);
            MainLoop.ProcessKeyboard();
            World.UpdateMouseGrab(TimeElapsed);
            MainLoop.ProcessControls(TimeElapsed);
            for (int i = 0; i < JoystickManager.AttachedJoysticks.Length; i++)
            {
                var railDriver = JoystickManager.AttachedJoysticks[i] as JoystickManager.Raildriver;
                if (railDriver != null)
                {
                    if (Interface.CurrentOptions.RailDriverMPH)
                    {
                        railDriver.SetDisplay((int)(TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Specs
                                                    .CurrentPerceivedSpeed * 2.23694));
                    }
                    else
                    {
                        railDriver.SetDisplay((int)(TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Specs
                                                    .CurrentPerceivedSpeed * 3.6));
                    }
                }
            }
            RenderRealTimeElapsed = 0.0;
            RenderTimeElapsed     = 0.0;



#if DEBUG
            MainLoop.CheckForOpenGlError("MainLoop");
#endif
            if (Interface.CurrentOptions.UnloadUnusedTextures)
            {
                Renderer.UnloadUnusedTextures(TimeElapsed);
                Renderer.LastBoundTexture = null;
            }
            // finish
            try
            {
                Interface.SaveLogs();
            }
            catch { }
        }
Пример #44
0
 // load bve 2 sound
 private static void LoadBve2Sound(string TrainPath, 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].DriverX, train.Cars[train.DriverCar].DriverY, train.Cars[train.DriverCar].DriverZ - 0.5);
     Vector3 panel = new Vector3(train.Cars[train.DriverCar].DriverX, train.Cars[train.DriverCar].DriverY, train.Cars[train.DriverCar].DriverZ + 1.0);
     const double large = 30.0;
     const double medium = 10.0;
     const double small = 5.0;
     const double tiny = 2.0;
     LoadNoSound(train);
     // load sounds for driver's car
     train.Cars[train.DriverCar].Sounds.Adjust = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Adjust.wav"), panel, tiny);
     train.Cars[train.DriverCar].Sounds.Brake = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Brake.wav"), center, small);
     train.Cars[train.DriverCar].Sounds.Halt = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Halt.wav"), cab, tiny);
     train.Cars[train.DriverCar].Sounds.Horns[0].Sound = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Klaxon0.wav"), front, large);
     train.Cars[train.DriverCar].Sounds.Horns[0].Loop = false;
     if (train.Cars[train.DriverCar].Sounds.Horns[0].Sound.Buffer == null) {
         train.Cars[train.DriverCar].Sounds.Horns[0].Sound = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Klaxon.wav"), front, large);
     }
     train.Cars[train.DriverCar].Sounds.Horns[1].Sound = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Klaxon1.wav"), front, large);
     train.Cars[train.DriverCar].Sounds.Horns[1].Loop = false;
     train.Cars[train.DriverCar].Sounds.Horns[2].Sound = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Klaxon2.wav"), front, medium);
     train.Cars[train.DriverCar].Sounds.Horns[2].Loop = true;
     train.Cars[train.DriverCar].Sounds.PilotLampOn = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Leave.wav"), cab, tiny);
     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].FrontAxlePosition);
         Vector3 rearaxle = new Vector3(0.0, 0.0, train.Cars[i].RearAxlePosition);
         train.Cars[i].Sounds.Air = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Air.wav"), center, small);
         train.Cars[i].Sounds.AirHigh = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "AirHigh.wav"), center, small);
         train.Cars[i].Sounds.AirZero = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "AirZero.wav"), center, small);
         if (train.Cars[i].Specs.AirBrake.Type == TrainManager.AirBrakeType.Main) {
             train.Cars[i].Sounds.CpEnd = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "CpEnd.wav"), center, medium);
             train.Cars[i].Sounds.CpLoop = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "CpLoop.wav"), center, medium);
             train.Cars[i].Sounds.CpStart = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "CpStart.wav"), center, medium);
         }
         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 = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorClsL.wav"), left, small);
         train.Cars[i].Sounds.DoorCloseR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorClsR.wav"), right, small);
         if (train.Cars[i].Sounds.DoorCloseL.Buffer == null) {
             train.Cars[i].Sounds.DoorCloseL = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorCls.wav"), left, small);
         }
         if (train.Cars[i].Sounds.DoorCloseR.Buffer == null) {
             train.Cars[i].Sounds.DoorCloseR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorCls.wav"), right, small);
         }
         train.Cars[i].Sounds.DoorOpenL = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorOpnL.wav"), left, small);
         train.Cars[i].Sounds.DoorOpenR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorOpnR.wav"), right, small);
         if (train.Cars[i].Sounds.DoorOpenL.Buffer == null) {
             train.Cars[i].Sounds.DoorOpenL = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorOpn.wav"), left, small);
         }
         if (train.Cars[i].Sounds.DoorOpenR.Buffer == null) {
             train.Cars[i].Sounds.DoorOpenR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "DoorOpn.wav"), right, small);
         }
         train.Cars[i].Sounds.EmrBrake = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "EmrBrake.wav"), center, medium);
         train.Cars[i].Sounds.Flange = TryLoadSoundArray(TrainPath, "Flange", ".wav", center, medium);
         train.Cars[i].Sounds.FlangeVolume = new double[train.Cars[i].Sounds.Flange.Length];
         train.Cars[i].Sounds.Loop = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Loop.wav"), center, medium);
         train.Cars[i].Sounds.PointFrontAxle = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Point.wav"), frontaxle, small);
         train.Cars[i].Sounds.PointRearAxle = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Point.wav"), rearaxle, small);
         train.Cars[i].Sounds.Rub = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Rub.wav"), center, medium);
         train.Cars[i].Sounds.Run = TryLoadSoundArray(TrainPath, "Run", ".wav", center, medium);
         train.Cars[i].Sounds.RunVolume = new double[train.Cars[i].Sounds.Run.Length];
         train.Cars[i].Sounds.SpringL = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "SpringL.wav"), left, small);
         train.Cars[i].Sounds.SpringR = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "SpringR.wav"), right, small);
         // 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 = TryLoadSound(OpenBveApi.Path.CombineFile(TrainPath, "Motor" + idx.ToString(Culture) + ".wav"), center, medium);
                         train.Cars[i].Sounds.Motor.Tables[j].Entries[k].Buffer = snd.Buffer;
                     }
                 }
             }
         }
     }
 }
Пример #45
0
 internal static void UpdateAnimatedObject(ref AnimatedObject Object, bool IsPartOfTrain, TrainManager.Train Train, int CarIndex, int SectionIndex, double TrackPosition, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, bool Overlay, bool UpdateFunctions, bool Show, double TimeElapsed)
 {
     int s = Object.CurrentState;
     int i = Object.ObjectIndex;
     // state change
     if (Object.StateFunction != null & UpdateFunctions) {
         double sd = Object.StateFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         int si = (int)Math.Round(sd);
         int sn = Object.States.Length;
         if (si < 0 | si >= sn) si = -1;
         if (s != si) {
             InitializeAnimatedObject(ref Object, si, Overlay, Show);
             s = si;
         }
     }
     if (s == -1) return;
     // translation
     if (Object.TranslateXFunction != null) {
         double x;
         if (UpdateFunctions) {
             x = Object.TranslateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         } else  {
             x = Object.TranslateXFunction.LastResult;
         }
         double rx = Object.TranslateXDirection.X, ry = Object.TranslateXDirection.Y, rz = Object.TranslateXDirection.Z;
         World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z);
         Position.X += x * rx;
         Position.Y += x * ry;
         Position.Z += x * rz;
     }
     if (Object.TranslateYFunction != null) {
         double y;
         if (UpdateFunctions) {
             y = Object.TranslateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         } else {
             y = Object.TranslateYFunction.LastResult;
         }
         double rx = Object.TranslateYDirection.X, ry = Object.TranslateYDirection.Y, rz = Object.TranslateYDirection.Z;
         World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z);
         Position.X += y * rx;
         Position.Y += y * ry;
         Position.Z += y * rz;
     }
     if (Object.TranslateZFunction != null) {
         double z;
         if (UpdateFunctions) {
             z = Object.TranslateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         } else {
             z = Object.TranslateZFunction.LastResult;
         }
         double rx = Object.TranslateZDirection.X, ry = Object.TranslateZDirection.Y, rz = Object.TranslateZDirection.Z;
         World.Rotate(ref rx, ref ry, ref rz, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z);
         Position.X += z * rx;
         Position.Y += z * ry;
         Position.Z += z * rz;
     }
     // rotation
     bool rotateX = Object.RotateXFunction != null;
     bool rotateY = Object.RotateYFunction != null;
     bool rotateZ = Object.RotateZFunction != null;
     double cosX, sinX;
     if (rotateX) {
         double a;
         if (UpdateFunctions) {
             a = Object.RotateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         } else {
             a = Object.RotateXFunction.LastResult;
         }
         ObjectManager.UpdateDamping(ref Object.RotateXDamping, TimeElapsed, ref a);
         cosX = Math.Cos(a);
         sinX = Math.Sin(a);
     } else {
         cosX = 0.0; sinX = 0.0;
     }
     double cosY, sinY;
     if (rotateY) {
         double a;
         if (UpdateFunctions) {
             a = Object.RotateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         } else {
             a = Object.RotateYFunction.LastResult;
         }
         ObjectManager.UpdateDamping(ref Object.RotateYDamping, TimeElapsed, ref a);
         cosY = Math.Cos(a);
         sinY = Math.Sin(a);
     } else {
         cosY = 0.0; sinY = 0.0;
     }
     double cosZ, sinZ;
     if (rotateZ) {
         double a;
         if (UpdateFunctions) {
             a = Object.RotateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         } else {
             a = Object.RotateZFunction.LastResult;
         }
         ObjectManager.UpdateDamping(ref Object.RotateZDamping, TimeElapsed, ref a);
         cosZ = Math.Cos(a);
         sinZ = Math.Sin(a);
     } else {
         cosZ = 0.0; sinZ = 0.0;
     }
     // texture shift
     bool shiftx = Object.TextureShiftXFunction != null;
     bool shifty = Object.TextureShiftYFunction != null;
     if ((shiftx | shifty) & UpdateFunctions) {
         for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) {
             ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates = Object.States[s].Object.Mesh.Vertices[k].TextureCoordinates;
         }
         if (shiftx) {
             double x = Object.TextureShiftXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
             x -= Math.Floor(x);
             for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) {
                 ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(x * Object.TextureShiftXDirection.X);
                 ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(x * Object.TextureShiftXDirection.Y);
             }
         }
         if (shifty) {
             double y = Object.TextureShiftYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
             y -= Math.Floor(y);
             for (int k = 0; k < ObjectManager.Objects[i].Mesh.Vertices.Length; k++) {
                 ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.X += (float)(y * Object.TextureShiftYDirection.X);
                 ObjectManager.Objects[i].Mesh.Vertices[k].TextureCoordinates.Y += (float)(y * Object.TextureShiftYDirection.Y);
             }
         }
     }
     // led
     bool led = Object.LEDFunction != null;
     double ledangle;
     if (led) {
         if (UpdateFunctions) {
             double lastangle = Object.LEDFunction.LastResult;
             ledangle = Object.LEDFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed);
         } else {
             ledangle = Object.LEDFunction.LastResult;
         }
     } else {
         ledangle = 0.0;
     }
     // null object
     if (Object.States[s].Object == null) {
         return;
     }
     // initialize vertices
     for (int k = 0; k < Object.States[s].Object.Mesh.Vertices.Length; k++) {
         ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates = Object.States[s].Object.Mesh.Vertices[k].Coordinates;
     }
     // led
     if (led) {
         /*
          * Edges:         Vertices:
          * 0 - bottom     0 - bottom-left
          * 1 - left       1 - top-left
          * 2 - top        2 - top-right
          * 3 - right      3 - bottom-right
          *                4 - center
          * */
         int v = 1;
         if (Object.LEDClockwiseWinding) {
             /* winding is clockwise*/
             if (ledangle < Object.LEDInitialAngle) {
                 ledangle = Object.LEDInitialAngle;
             }
             if (ledangle < Object.LEDLastAngle) {
                 double currentEdgeFloat = Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449));
                 int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4;
                 double lastEdgeFloat = Math.Floor(0.636619772367582 * (Object.LEDLastAngle + 0.785398163397449));
                 int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4;
                 if (lastEdge < currentEdge | lastEdge == currentEdge & Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) {
                     lastEdge += 4;
                 }
                 if (currentEdge == lastEdge) {
                     /* current angle to last angle */
                     {
                         double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge].X;
                         double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge].Y;
                         double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge].Z;
                         Object.States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz);
                         v++;
                     }
                     {
                         double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge].X;
                         double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge].Y;
                         double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge].Z;
                         Object.States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz);
                         v++;
                     }
                 } else {
                     {
                         /* current angle to square vertex */
                         double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge].X;
                         double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge].Y;
                         double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge].Z;
                         Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = new Vector3(cx, cy, cz);
                         Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[currentEdge];
                         v += 2;
                     }
                     for (int j = currentEdge + 1; j < lastEdge; j++) {
                         /* square-vertex to square-vertex */
                         Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(j + 3) % 4];
                         Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[j % 4];
                         v += 2;
                     }
                     {
                         /* square vertex to last angle */
                         double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge % 4].X;
                         double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge % 4].Y;
                         double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge % 4].Z;
                         Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(lastEdge + 3) % 4];
                         Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = new Vector3(lx, ly, lz);
                         v += 2;
                     }
                 }
             }
         } else {
             /* winding is counter-clockwise*/
             if (ledangle > Object.LEDInitialAngle) {
                 ledangle = Object.LEDInitialAngle;
             }
             if (ledangle > Object.LEDLastAngle) {
                 double currentEdgeFloat = Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449));
                 int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4;
                 double lastEdgeFloat = Math.Floor(0.636619772367582 * (Object.LEDLastAngle + 0.785398163397449));
                 int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4;
                 if (currentEdge < lastEdge | lastEdge == currentEdge & Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) {
                     currentEdge += 4;
                 }
                 if (currentEdge == lastEdge) {
                     /* current angle to last angle */
                     {
                         double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge].X;
                         double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge].Y;
                         double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge].Z;
                         Object.States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz);
                         v++;
                     }
                     {
                         double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = t - Math.Floor(t);
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge].X;
                         double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge].Y;
                         double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge].Z;
                         Object.States[s].Object.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz);
                         v++;
                     }
                 } else {
                     {
                         /* current angle to square vertex */
                         double t = 0.5 + (0.636619772367582 * ledangle) - currentEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double cx = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].X + t * Object.LEDVectors[currentEdge % 4].X;
                         double cy = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Y + t * Object.LEDVectors[currentEdge % 4].Y;
                         double cz = (1.0 - t) * Object.LEDVectors[(currentEdge + 3) % 4].Z + t * Object.LEDVectors[currentEdge % 4].Z;
                         Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(currentEdge + 3) % 4];
                         Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = new Vector3(cx, cy, cz);
                         v += 2;
                     }
                     for (int j = currentEdge - 1; j > lastEdge; j--) {
                         /* square-vertex to square-vertex */
                         Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = Object.LEDVectors[(j + 3) % 4];
                         Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[j % 4];
                         v += 2;
                     }
                     {
                         /* square vertex to last angle */
                         double t = 0.5 + (0.636619772367582 * Object.LEDLastAngle) - lastEdgeFloat;
                         if (t < 0.0) {
                             t = 0.0;
                         } else if (t > 1.0) {
                             t = 1.0;
                         }
                         t = 0.5 * (1.0 - Math.Tan(0.25 * (Math.PI - 2.0 * Math.PI * t)));
                         double lx = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].X + t * Object.LEDVectors[lastEdge].X;
                         double ly = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Y + t * Object.LEDVectors[lastEdge].Y;
                         double lz = (1.0 - t) * Object.LEDVectors[(lastEdge + 3) % 4].Z + t * Object.LEDVectors[lastEdge].Z;
                         Object.States[s].Object.Mesh.Vertices[v + 0].Coordinates = new Vector3(lx, ly, lz);
                         Object.States[s].Object.Mesh.Vertices[v + 1].Coordinates = Object.LEDVectors[lastEdge % 4];
                         v += 2;
                     }
                 }
             }
         }
         for (int j = v; v < 11; v++) {
             Object.States[s].Object.Mesh.Vertices[j].Coordinates = Object.LEDVectors[4];
         }
     }
     // update vertices
     for (int k = 0; k < Object.States[s].Object.Mesh.Vertices.Length; k++) {
         // rotate
         if (rotateX) {
             World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateXDirection.X, Object.RotateXDirection.Y, Object.RotateXDirection.Z, cosX, sinX);
         }
         if (rotateY) {
             World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateYDirection.X, Object.RotateYDirection.Y, Object.RotateYDirection.Z, cosY, sinY);
         }
         if (rotateZ) {
             World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Object.RotateZDirection.X, Object.RotateZDirection.Y, Object.RotateZDirection.Z, cosZ, sinZ);
         }
         // translate
         if (Overlay & World.CameraRestriction != World.CameraRestrictionMode.NotAvailable) {
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Object.States[s].Position.X - Position.X;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Object.States[s].Position.Y - Position.Y;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Object.States[s].Position.Z - Position.Z;
             World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, World.AbsoluteCameraDirection.X, World.AbsoluteCameraDirection.Y, World.AbsoluteCameraDirection.Z, World.AbsoluteCameraUp.X, World.AbsoluteCameraUp.Y, World.AbsoluteCameraUp.Z, World.AbsoluteCameraSide.X, World.AbsoluteCameraSide.Y, World.AbsoluteCameraSide.Z);
             double dx = -Math.Tan(World.CameraCurrentAlignment.Yaw) - World.CameraCurrentAlignment.Position.X;
             double dy = -Math.Tan(World.CameraCurrentAlignment.Pitch) - World.CameraCurrentAlignment.Position.Y;
             double dz = -World.CameraCurrentAlignment.Position.Z;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += World.AbsoluteCameraPosition.X + dx * World.AbsoluteCameraSide.X + dy * World.AbsoluteCameraUp.X + dz * World.AbsoluteCameraDirection.X;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += World.AbsoluteCameraPosition.Y + dx * World.AbsoluteCameraSide.Y + dy * World.AbsoluteCameraUp.Y + dz * World.AbsoluteCameraDirection.Y;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += World.AbsoluteCameraPosition.Z + dx * World.AbsoluteCameraSide.Z + dy * World.AbsoluteCameraUp.Z + dz * World.AbsoluteCameraDirection.Z;
         } else {
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Object.States[s].Position.X;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Object.States[s].Position.Y;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Object.States[s].Position.Z;
             World.Rotate(ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y, ref ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z);
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.X += Position.X;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Y += Position.Y;
             ObjectManager.Objects[i].Mesh.Vertices[k].Coordinates.Z += Position.Z;
         }
     }
     // update normals
     for (int k = 0; k < Object.States[s].Object.Mesh.Faces.Length; k++) {
         for (int h = 0; h < Object.States[s].Object.Mesh.Faces[k].Vertices.Length; h++) {
             ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal = Object.States[s].Object.Mesh.Faces[k].Vertices[h].Normal;
         }
         for (int h = 0; h < Object.States[s].Object.Mesh.Faces[k].Vertices.Length; h++) {
             if (!Object.States[s].Object.Mesh.Faces[k].Vertices[h].Normal.IsZero()) {
                 if (rotateX) {
                     World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateXDirection.X, Object.RotateXDirection.Y, Object.RotateXDirection.Z, cosX, sinX);
                 }
                 if (rotateY) {
                     World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateYDirection.X, Object.RotateYDirection.Y, Object.RotateYDirection.Z, cosY, sinY);
                 }
                 if (rotateZ) {
                     World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Object.RotateZDirection.X, Object.RotateZDirection.Y, Object.RotateZDirection.Z, cosZ, sinZ);
                 }
                 World.Rotate(ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.X, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Y, ref ObjectManager.Objects[i].Mesh.Faces[k].Vertices[h].Normal.Z, Direction.X, Direction.Y, Direction.Z, Up.X, Up.Y, Up.Z, Side.X, Side.Y, Side.Z);
             }
         }
         // visibility changed
         if (Show) {
             if (Overlay) {
                 Renderer.ShowObject(i, Renderer.ObjectType.Overlay);
             } else {
                 Renderer.ShowObject(i, Renderer.ObjectType.Dynamic);
             }
         } else {
             Renderer.HideObject(i);
         }
     }
 }
Пример #46
0
 // ================================
 // parse panel config
 internal static void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding, TrainManager.Train Train)
 {
     string File = OpenBveApi.Path.CombineFile(TrainPath, "panel.animated");
     if (System.IO.File.Exists(File)) {
         ObjectManager.AnimatedObjectCollection a = AnimatedObjectParser.ReadObject(File, Encoding, ObjectManager.ObjectLoadMode.DontAllowUnloadOfTextures);
         for (int i = 0; i < a.Objects.Length; i++) {
             a.Objects[i].ObjectIndex = ObjectManager.CreateDynamicObject();
         }
         Train.Cars[Train.DriverCar].CarSections[0].Elements = a.Objects;
         World.CameraRestriction = World.CameraRestrictionMode.NotAvailable;
     } else {
         File = OpenBveApi.Path.CombineFile(TrainPath, "panel2.cfg");
         if (System.IO.File.Exists(File)) {
             Panel2CfgParser.ParsePanel2Config(TrainPath, Encoding, Train);
             World.CameraRestriction = World.CameraRestrictionMode.On;
         } else {
             File = OpenBveApi.Path.CombineFile(TrainPath, "panel.cfg");
             if (System.IO.File.Exists(File)) {
                 PanelCfgParser.ParsePanelConfig(TrainPath, Encoding, Train);
                 World.CameraRestriction = World.CameraRestrictionMode.On;
             } else {
                 World.CameraRestriction = World.CameraRestrictionMode.NotAvailable;
             }
         }
     }
 }
Пример #47
0
            public override void Trigger(double TimeElapsed)
            {
                if (Program.CurrentRoute.SecondsSinceMidnight == TimeLastProcessed)
                {
                    return;
                }

                // Initialize
                if (TimeLastProcessed == 0.0)
                {
                    SetupTravelData(Program.CurrentRoute.SecondsSinceMidnight);
                    CheckTravelData(Program.CurrentRoute.SecondsSinceMidnight);
                    CurrentPosition = Data[0].Position;
                }

                TimeLastProcessed = Program.CurrentRoute.SecondsSinceMidnight;

                // Dispose the train if it is past the leave time of the train
                if (LeaveTime > AppearanceTime && Program.CurrentRoute.SecondsSinceMidnight >= LeaveTime)
                {
                    Train.Dispose();
                    return;
                }

                // Calculate the position where the train is at the present time.
                double          NewMileage;
                double          NewPosition;
                TravelDirection NewDirection;
                bool            OpenLeftDoors;
                bool            OpenRightDoors;

                GetNewState(Program.CurrentRoute.SecondsSinceMidnight, out NewMileage, out NewPosition, out NewDirection, out OpenLeftDoors, out OpenRightDoors);

                // Calculate the travel distance of the train.
                double DeltaPosition = NewPosition - CurrentPosition;

                // Set the state quantity of the train.
                if (DeltaPosition < 0)
                {
                    Train.Handles.Reverser.Driver = TrainManager.ReverserPosition.Reverse;
                }
                else if (DeltaPosition > 0)
                {
                    Train.Handles.Reverser.Driver = TrainManager.ReverserPosition.Forwards;
                }
                Train.Handles.Reverser.Actual = Train.Handles.Reverser.Driver;

                TrainManager.OpenTrainDoors(Train, OpenLeftDoors, OpenRightDoors);
                TrainManager.CloseTrainDoors(Train, !OpenLeftDoors, !OpenRightDoors);

                if (TimeElapsed != 0.0)
                {
                    Train.CurrentSpeed = DeltaPosition / TimeElapsed;
                    Train.Specs.CurrentAverageAcceleration = Math.Sign(Train.CurrentSpeed) * Train.CurrentSpeed / TimeElapsed;
                }
                else
                {
                    Train.CurrentSpeed = 0.0;
                    Train.Specs.CurrentAverageAcceleration = 0.0;
                }

                foreach (var Car in Train.Cars)
                {
                    SetRailIndex(NewMileage, NewDirection, Car.FrontAxle.Follower);
                    SetRailIndex(NewMileage, NewDirection, Car.RearAxle.Follower);
                    SetRailIndex(NewMileage, NewDirection, Car.FrontBogie.FrontAxle.Follower);
                    SetRailIndex(NewMileage, NewDirection, Car.FrontBogie.RearAxle.Follower);
                    SetRailIndex(NewMileage, NewDirection, Car.RearBogie.FrontAxle.Follower);
                    SetRailIndex(NewMileage, NewDirection, Car.RearBogie.RearAxle.Follower);

                    Car.Move(DeltaPosition);

                    Car.CurrentSpeed = Train.CurrentSpeed;
                    Car.Specs.CurrentPerceivedSpeed     = Train.CurrentSpeed;
                    Car.Specs.CurrentAcceleration       = Train.Specs.CurrentAverageAcceleration;
                    Car.Specs.CurrentAccelerationOutput = Train.Specs.CurrentAverageAcceleration;
                }

                CurrentPosition = NewPosition;
            }
Пример #48
0
 /// <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.Vector3 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];
 }
Пример #49
0
        //
        // PROCESS MENU COMMAND
        //
        /// <summary>Processes a user command for the current menu</summary>
        /// <param name="cmd">The command to apply to the current menu</param>
        /// <param name="timeElapsed">The time elapsed since previous frame</param>
        internal void ProcessCommand(Translations.Command cmd, double timeElapsed)
        {
            if (CurrMenu < 0)
            {
                return;
            }
            // MenuBack is managed independently from single menu data
            if (cmd == Translations.Command.MenuBack)
            {
                PopMenu();
                return;
            }

            SingleMenu menu = Menus[CurrMenu];

            if (menu.Selection == SelectionNone)                // if menu has no selection, do nothing
            {
                return;
            }
            switch (cmd)
            {
            case Translations.Command.MenuUp:                          // UP
                if (menu.Selection > 0 &&
                    !(menu.Items[menu.Selection - 1] is MenuCaption))
                {
                    menu.Selection--;
                    PositionMenu();
                }
                break;

            case Translations.Command.MenuDown:                        // DOWN
                if (menu.Selection < menu.Items.Length - 1)
                {
                    menu.Selection++;
                    PositionMenu();
                }
                break;

            //			case Translations.Command.MenuBack:	// ESC:	managed above
            //				break;
            case Translations.Command.MenuEnter:                       // ENTER
                if (menu.Items[menu.Selection] is MenuCommand)
                {
                    MenuCommand menuItem = (MenuCommand)menu.Items[menu.Selection];
                    switch (menuItem.Tag)
                    {
                    // menu management commands
                    case MenuTag.MenuBack:                                                  // BACK TO PREVIOUS MENU
                        Menu.instance.PopMenu();
                        break;

                    case MenuTag.MenuJumpToStation:                                         // TO STATIONS MENU
                        Menu.instance.PushMenu(MenuType.JumpToStation);
                        break;

                    case MenuTag.MenuExitToMainMenu:                                        // TO EXIT MENU
                        Menu.instance.PushMenu(MenuType.ExitToMainMenu);
                        break;

                    case MenuTag.MenuQuit:                                                  // TO QUIT MENU
                        Menu.instance.PushMenu(MenuType.Quit);
                        break;

                    case MenuTag.MenuControls:                                              // TO CONTROLS MENU
                        Menu.instance.PushMenu(MenuType.Controls);
                        break;

                    case MenuTag.BackToSim:                                                 // OUT OF MENU BACK TO SIMULATION
                        Reset();
                        Game.PreviousInterface = Game.InterfaceType.Menu;
                        Game.CurrentInterface  = Game.InterfaceType.Normal;
                        break;

                    // simulation commands
                    case MenuTag.JumpToStation:                                             // JUMP TO STATION
                        Reset();
                        TrainManager.JumpTrain(TrainManager.PlayerTrain, menuItem.Data);
                        TrainManager.JumpTFO();
                        break;

                    case MenuTag.ExitToMainMenu:                                            // BACK TO MAIN MENU
                        Reset();
                        Program.RestartArguments =
                            Interface.CurrentOptions.GameMode == GameMode.Arcade ? "/review" : "";
                        MainLoop.Quit = MainLoop.QuitMode.ExitToMenu;
                        break;

                    case MenuTag.Control:                                                   // CONTROL CUSTOMIZATION
                        PushMenu(MenuType.Control, ((MenuCommand)menu.Items[menu.Selection]).Data);
                        isCustomisingControl = true;
                        CustomControlIdx     = ((MenuCommand)menu.Items[menu.Selection]).Data;
                        break;

                    case MenuTag.Quit:                                                      // QUIT PROGRAMME
                        Reset();
                        MainLoop.Quit = MainLoop.QuitMode.QuitProgram;
                        break;
                    }
                }
                break;

            case Translations.Command.MiscFullscreen:
                // fullscreen
                Screen.ToggleFullscreen();
                break;

            case Translations.Command.MiscMute:
                // mute
                Program.Sounds.GlobalMute = !Program.Sounds.GlobalMute;
                Program.Sounds.Update(timeElapsed, Interface.CurrentOptions.SoundModel);
                break;
            }
        }
Пример #50
0
        /// <summary>Updates the sound component. Should be called every frame.</summary>
        /// <param name="timeElapsed">The time in seconds that elapsed since the last call to this function.</param>
        private static void UpdateInverseModel(double timeElapsed)
        {
            /*
             * Set up the listener.
             * */
            OpenBveApi.Math.Vector3D     listenerPosition    = World.AbsoluteCameraPosition;
            OpenBveApi.Math.Orientation3 listenerOrientation = new OpenBveApi.Math.Orientation3(World.AbsoluteCameraSide, World.AbsoluteCameraUp, World.AbsoluteCameraDirection);
            OpenBveApi.Math.Vector3D     listenerVelocity;
            if (World.CameraMode == World.CameraViewMode.Interior || World.CameraMode == World.CameraViewMode.InteriorLookAhead || World.CameraMode == World.CameraViewMode.Exterior)
            {
                TrainManager.Car         car  = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar];
                OpenBveApi.Math.Vector3D diff = car.FrontAxle.Follower.WorldPosition - car.RearAxle.Follower.WorldPosition;
                if (diff.IsNullVector())
                {
                    listenerVelocity = car.Specs.CurrentSpeed * OpenBveApi.Math.Vector3D.Forward;
                }
                else
                {
                    listenerVelocity = car.Specs.CurrentSpeed * OpenBveApi.Math.Vector3D.Normalize(diff);
                }
            }
            else
            {
                listenerVelocity = OpenBveApi.Math.Vector3D.Null;
            }
            float[] vectors =
            {
                (float)listenerOrientation.Z.X,
                (float)listenerOrientation.Z.Y,
                (float)listenerOrientation.Z.Z,
                -(float)listenerOrientation.Y.X,
                -(float)listenerOrientation.Y.Y,
                -(float)listenerOrientation.Y.Z
            };
            AL.Listener(ALListener3f.Position, 0.0f, 0.0f, 0.0f);
            AL.Listener(ALListener3f.Velocity, (float)listenerVelocity.X, (float)listenerVelocity.Y, (float)listenerVelocity.Z);
            AL.Listener(ALListenerfv.Orientation, ref vectors);

            /*
             * Set up the atmospheric attributes.
             * */
            double elevation      = World.AbsoluteCameraPosition.Y + Game.RouteInitialElevation;
            double airTemperature = Game.GetAirTemperature(elevation);
            double airPressure    = Game.GetAirPressure(elevation, airTemperature);
            // double airDensity = Game.GetAirDensity(airPressure, airTemperature);
            double speedOfSound = Game.GetSpeedOfSound(airPressure, airTemperature);

            try {
                AL.SpeedOfSound((float)speedOfSound);
            } catch { }

            /*
             * Collect all sounds that are to be played
             * and ensure that all others are stopped.
             * */
            List <SoundSourceAttenuation> toBePlayed = new List <SoundSourceAttenuation>();

            for (int i = 0; i < SourceCount; i++)
            {
                if (Sources[i].State == SoundSourceState.StopPending)
                {
                    /*
                     * The sound is still playing but is to be stopped.
                     * Stop the sound, then remove it from the list of
                     * sound sources.
                     * */
                    AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                    Sources[i].State            = SoundSourceState.Stopped;
                    Sources[i].OpenAlSourceName = 0;
                    Sources[i] = Sources[SourceCount - 1];
                    SourceCount--;
                    i--;
                }
                else if (Sources[i].State == SoundSourceState.Stopped)
                {
                    /*
                     * The sound was already stopped. Remove it from
                     * the list of sound sources.
                     * */
                    Sources[i] = Sources[SourceCount - 1];
                    SourceCount--;
                    i--;
                }
                else if (GlobalMute)
                {
                    /*
                     * The sound is playing or about to be played, but
                     * the global mute option is enabled. Stop the sound
                     * sound if necessary, then remove it from the list
                     * of sound sources if the sound is not looping.
                     * */
                    if (Sources[i].State == SoundSourceState.Playing)
                    {
                        AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                        Sources[i].State            = SoundSourceState.PlayPending;
                        Sources[i].OpenAlSourceName = 0;
                    }
                    if (!Sources[i].Looped)
                    {
                        Sources[i].State            = SoundSourceState.Stopped;
                        Sources[i].OpenAlSourceName = 0;
                        Sources[i] = Sources[SourceCount - 1];
                        SourceCount--;
                        i--;
                    }
                }
                else
                {
                    /*
                     * The sound is to be played or is already playing.
                     * */
                    if (Sources[i].State == SoundSourceState.Playing)
                    {
                        int state;
                        AL.GetSource(Sources[i].OpenAlSourceName, ALGetSourcei.SourceState, out state);
                        if (state != (int)ALSourceState.Initial && state != (int)ALSourceState.Playing)
                        {
                            /*
                             * The sound is not playing any longer.
                             * Remove it from the list of sound sources.
                             * */
                            AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                            Sources[i].State            = SoundSourceState.Stopped;
                            Sources[i].OpenAlSourceName = 0;
                            Sources[i] = Sources[SourceCount - 1];
                            SourceCount--;
                            i--;
                            continue;
                        }
                    }

                    /*
                     * Calculate the gain, then add the sound
                     * to the list of sounds to be played.
                     * */
                    OpenBveApi.Math.Vector3D position;
                    if (Sources[i].Train != null)
                    {
                        OpenBveApi.Math.Vector3D direction;
                        TrainManager.CreateWorldCoordinates(Sources[i].Train, Sources[i].Car, Sources[i].Position.X, Sources[i].Position.Y, Sources[i].Position.Z, out position.X, out position.Y, out position.Z, out direction.X, out direction.Y, out direction.Z);
                    }
                    else
                    {
                        position = Sources[i].Position;
                    }
                    OpenBveApi.Math.Vector3D positionDifference = position - listenerPosition;
                    double distance = positionDifference.Norm();
                    double radius   = Sources[i].Radius;
                    if (World.CameraMode == World.CameraViewMode.Interior || World.CameraMode == World.CameraViewMode.InteriorLookAhead)
                    {
                        if (Sources[i].Train != TrainManager.PlayerTrain || Sources[i].Car != TrainManager.PlayerTrain.DriverCar)
                        {
                            radius *= 0.5;
                        }
                    }
                    double gain;
                    if (distance < 2.0 * radius)
                    {
                        gain = 1.0 - distance * distance * (4.0 * radius - distance) / (16.0 * radius * radius * radius);
                    }
                    else
                    {
                        gain = radius / distance;
                    }
                    gain *= Sources[i].Volume;
                    if (gain <= 0.0)
                    {
                        /*
                         * The gain is too low. Stop the sound if playing,
                         * but keep looping sounds pending.
                         * */
                        if (Sources[i].State == SoundSourceState.Playing)
                        {
                            AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                            Sources[i].State            = SoundSourceState.PlayPending;
                            Sources[i].OpenAlSourceName = 0;
                        }
                        if (!Sources[i].Looped)
                        {
                            Sources[i].State            = SoundSourceState.Stopped;
                            Sources[i].OpenAlSourceName = 0;
                            Sources[i] = Sources[SourceCount - 1];
                            SourceCount--;
                            i--;
                        }
                    }
                    else
                    {
                        /*
                         * Add the source.
                         * */
                        toBePlayed.Add(new SoundSourceAttenuation(Sources[i], gain, distance));
                    }
                }
            }

            /*
             * Now that we have the list of sounds that are to be played,
             * sort them by their gain so that we can determine and
             * adjust the clamp factor.
             * */
            double clampFactor = Math.Exp(LogClampFactor);

            for (int i = 0; i < toBePlayed.Count; i++)
            {
                toBePlayed[i].Gain -= clampFactor * toBePlayed[i].Distance * toBePlayed[i].Distance;
            }
            toBePlayed.Sort();
            for (int i = 0; i < toBePlayed.Count; i++)
            {
                toBePlayed[i].Gain += clampFactor * toBePlayed[i].Distance * toBePlayed[i].Distance;
            }
            double desiredLogClampFactor;
            int    index = Options.Current.SoundNumber;

            if (toBePlayed.Count <= index)
            {
                desiredLogClampFactor = MinLogClampFactor;
            }
            else
            {
                double cutoffDistance = toBePlayed[index].Distance;
                if (cutoffDistance <= 0.0)
                {
                    desiredLogClampFactor = MaxLogClampFactor;
                }
                else
                {
                    double cutoffGain = toBePlayed[index].Gain;
                    desiredLogClampFactor = Math.Log(cutoffGain / (cutoffDistance * cutoffDistance));
                    if (desiredLogClampFactor < MinLogClampFactor)
                    {
                        desiredLogClampFactor = MinLogClampFactor;
                    }
                    else if (desiredLogClampFactor > MaxLogClampFactor)
                    {
                        desiredLogClampFactor = MaxLogClampFactor;
                    }
                }
            }
            const double rate = 3.0;

            if (LogClampFactor < desiredLogClampFactor)
            {
                LogClampFactor += timeElapsed * rate;
                if (LogClampFactor > desiredLogClampFactor)
                {
                    LogClampFactor = desiredLogClampFactor;
                }
            }
            else if (LogClampFactor > desiredLogClampFactor)
            {
                LogClampFactor -= timeElapsed * rate;
                if (LogClampFactor < desiredLogClampFactor)
                {
                    LogClampFactor = desiredLogClampFactor;
                }
            }

            /*
             * Play the sounds.
             * */
            clampFactor = Math.Exp(LogClampFactor);
            for (int i = index; i < toBePlayed.Count; i++)
            {
                toBePlayed[i].Gain = 0.0;
            }
            for (int i = 0; i < toBePlayed.Count; i++)
            {
                SoundSource source = toBePlayed[i].Source;
                double      gain   = toBePlayed[i].Gain - clampFactor * toBePlayed[i].Distance * toBePlayed[i].Distance;
                if (gain <= 0.0)
                {
                    /*
                     * Stop the sound.
                     * */
                    if (source.State == SoundSourceState.Playing)
                    {
                        AL.DeleteSources(1, ref source.OpenAlSourceName);
                        source.State            = SoundSourceState.PlayPending;
                        source.OpenAlSourceName = 0;
                    }
                    if (!source.Looped)
                    {
                        source.State            = SoundSourceState.Stopped;
                        source.OpenAlSourceName = 0;
                    }
                }
                else
                {
                    /*
                     * Ensure the buffer is loaded, then play the sound.
                     * */
                    if (source.State != SoundSourceState.Playing)
                    {
                        LoadBuffer(source.Buffer);
                        if (source.Buffer.Loaded)
                        {
                            AL.GenSources(1, out source.OpenAlSourceName);
                            AL.Source(source.OpenAlSourceName, ALSourcei.Buffer, source.Buffer.OpenAlBufferName);
                        }
                        else
                        {
                            /*
                             * We cannot play the sound because
                             * the buffer could not be loaded.
                             * */
                            source.State = SoundSourceState.Stopped;
                            continue;
                        }
                    }
                    OpenBveApi.Math.Vector3D position;
                    OpenBveApi.Math.Vector3D velocity;
                    if (source.Train != null)
                    {
                        OpenBveApi.Math.Vector3D direction;
                        TrainManager.CreateWorldCoordinates(source.Train, source.Car, source.Position.X, source.Position.Y, source.Position.Z, out position.X, out position.Y, out position.Z, out direction.X, out direction.Y, out direction.Z);
                        velocity = source.Train.Cars[source.Car].Specs.CurrentSpeed * direction;
                    }
                    else
                    {
                        position = source.Position;
                        velocity = OpenBveApi.Math.Vector3D.Null;
                    }
                    position -= listenerPosition;
                    AL.Source(source.OpenAlSourceName, ALSource3f.Position, (float)position.X, (float)position.Y, (float)position.Z);
                    AL.Source(source.OpenAlSourceName, ALSource3f.Velocity, (float)velocity.X, (float)velocity.Y, (float)velocity.Z);
                    AL.Source(source.OpenAlSourceName, ALSourcef.Pitch, (float)source.Pitch);
                    AL.Source(source.OpenAlSourceName, ALSourcef.Gain, (float)gain);
                    if (source.State != SoundSourceState.Playing)
                    {
                        AL.Source(source.OpenAlSourceName, ALSourceb.Looping, source.Looped);
                        AL.SourcePlay(source.OpenAlSourceName);
                        source.State = SoundSourceState.Playing;
                    }
                }
            }
        }
Пример #51
0
		// parse panel config
		internal static void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding, TrainManager.Train Train) {
			// read lines
			System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
			string FileName = OpenBveApi.Path.CombineFile(TrainPath, "panel.cfg");
			string[] Lines = System.IO.File.ReadAllLines(FileName, Encoding);
			for (int i = 0; i < Lines.Length; i++) {
				Lines[i] = Lines[i].Trim();
				int j = Lines[i].IndexOf(';');
				if (j >= 0) {
					Lines[i] = Lines[i].Substring(0, j).TrimEnd();
				}
			}
			// initialize
			double FullWidth = 480, FullHeight = 440, SemiHeight = 240;
			double AspectRatio = FullWidth / FullHeight;
			double WorldWidth, WorldHeight;
			if (Screen.Width >= Screen.Height) {
				WorldWidth = 2.0 * Math.Tan(0.5 * World.HorizontalViewingAngle) * EyeDistance;
				WorldHeight = WorldWidth / AspectRatio;
			} else {
				WorldHeight = 2.0 * Math.Tan(0.5 * World.VerticalViewingAngle) * EyeDistance;
				WorldWidth = WorldHeight * AspectRatio;
			}
			World.CameraRestrictionBottomLeft = new Vector3(-0.5 * WorldWidth, -0.5 * WorldHeight, EyeDistance);
			World.CameraRestrictionTopRight = new Vector3(0.5 * WorldWidth, 0.5 * WorldHeight, EyeDistance);
			double WorldLeft = Train.Cars[Train.DriverCar].DriverX - 0.5 * WorldWidth;
			double WorldTop = Train.Cars[Train.DriverCar].DriverY + 0.5 * WorldHeight;
			double WorldZ = Train.Cars[Train.DriverCar].DriverZ;
			const double UpDownAngleConstant = -0.191986217719376;
			double PanelYaw = 0.0;
			double PanelPitch = UpDownAngleConstant;
			string PanelBackground = OpenBveApi.Path.CombineFile(TrainPath, "panel.bmp");
			// parse lines for panel and view
			for (int i = 0; i < Lines.Length; i++) {
				if (Lines[i].Length > 0) {
					if (Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal)) {
						string Section = Lines[i].Substring(1, Lines[i].Length - 2).Trim();
						switch (Section.ToLowerInvariant()) {
								// panel
							case "panel":
								i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
									int j = Lines[i].IndexOf('=');
									if (j >= 0) {
										string Key = Lines[i].Substring(0, j).TrimEnd();
										string Value = Lines[i].Substring(j + 1).TrimStart();
										switch (Key.ToLowerInvariant()) {
											case "background":
												if (Interface.ContainsInvalidPathChars(Value)) {
													Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
												} else {
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													PanelBackground = OpenBveApi.Path.CombineFile(TrainPath, Value);
													if (!System.IO.File.Exists(PanelBackground)) {
														Interface.AddMessage(Interface.MessageType.Error, true, "FileName " + PanelBackground + "could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													}
												}
												break;
										}
									} i++;
								} i--; break;
								// view
							case "view":
								i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
									int j = Lines[i].IndexOf('=');
									if (j >= 0) {
										string Key = Lines[i].Substring(0, j).TrimEnd();
										string Value = Lines[i].Substring(j + 1).TrimStart();
										switch (Key.ToLowerInvariant()) {
											case "yaw":
												{
													double yaw = 0.0;
													if (Value.Length > 0 && !Interface.TryParseDoubleVb6(Value, out yaw)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "ValueInDegrees is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														yaw = 0.0;
													}
													PanelYaw = Math.Atan(yaw);
												} break;
											case "pitch":
												{
													double pitch = 0.0;
													if (Value.Length > 0 && !Interface.TryParseDoubleVb6(Value, out pitch)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "ValueInDegrees is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														pitch = 0.0;
													}
													PanelPitch = Math.Atan(pitch) + UpDownAngleConstant;
												} break;
										}
									} i++;
								} i--; break;
						}
					}
				}
			}
			Train.Cars[Train.DriverCar].DriverYaw = PanelYaw;
			Train.Cars[Train.DriverCar].DriverPitch = PanelPitch;
			// panel
			{
				if (!System.IO.File.Exists(PanelBackground)) {
					Interface.AddMessage(Interface.MessageType.Error, true, "The panel image could not be found in " + FileName);
				} else {
					Textures.Texture t;
					Textures.RegisterTexture(PanelBackground, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t);
				    OpenBVEGame.RunInRenderThread(() =>
				    {
				        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp); 
                    });
					double w = (double)t.Width;
					double h = (double)t.Height;
					SemiHeight = FullHeight - h;
					CreateElement(Train, 0, SemiHeight, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
				}
			}
			// parse lines for rest
			double invfac = Lines.Length == 0 ? Loading.TrainProgressCurrentWeight : Loading.TrainProgressCurrentWeight / (double)Lines.Length;
			for (int i = 0; i < Lines.Length; i++) {
				Loading.TrainProgress = Loading.TrainProgressCurrentSum + invfac * (double)i;
				if ((i & 7) == 0) {
					System.Threading.Thread.Sleep(1);
					if (Loading.Cancel) return;
				}
				if (Lines[i].Length != 0) {
					if (Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal)) {
						string Section = Lines[i].Substring(1, Lines[i].Length - 2).Trim();
						switch (Section.ToLowerInvariant()) {
								// pressuregauge
							case "pressuregauge":
							case "pressuremeter":
							case "pressureindicator":
							case "圧力計":
								{
									int Type = 0;
									Color32[] NeedleColor = new Color32[] { new Color32(0, 0, 0, 255), new Color32(0, 0, 0, 255) };
									int[] NeedleType = new int[] { 0, 0 };
									double CenterX = 0.0, CenterY = 0.0, Radius = 16.0;
									string Background = null, Cover = null;
									double Angle = 0.785398163397449, Minimum = 0.0, Maximum = 1000.0;
									double UnitFactor = 1000.0;
									i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
										int j = Lines[i].IndexOf('='); if (j >= 0) {
											string Key = Lines[i].Substring(0, j).TrimEnd();
											string Value = Lines[i].Substring(j + 1).TrimStart();
											string[] Arguments = GetArguments(Value);
											switch (Key.ToLowerInvariant()) {
												case "type":
												case "形態":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseIntVb6(Arguments[0], out Type)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Type is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Type = 0;
													} else if (Type != 0 & Type != 1) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Type must be either 0 or 1 in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Type = 0;
													} break;
												case "lowerneedle":
												case "lowerhand":
												case "下針":
												case "upperneedle":
												case "upperhand":
												case "上針":
													int k = Key.ToLowerInvariant() == "lowerneedle" | Key.ToLowerInvariant() == "lowerhand" | Key == "下針" ? 0 : 1;
													if (Arguments.Length >= 1 && Arguments[0].Length > 0) {
														switch (Arguments[0].ToLowerInvariant()) {
															case "bc":
															case "ブレーキシリンダ":
																NeedleType[k] = 1; break;
															case "sap":
															case "直通管":
																NeedleType[k] = 2; break;
															case "bp":
															case "ブレーキ管":
															case "制動管":
																NeedleType[k] = 3; break;
															case "er":
															case "釣り合い空気溜め":
															case "釣り合い空気ダメ":
															case "つりあい空気溜め":
															case "ツリアイ空気ダメ":
																NeedleType[k] = 4; break;
															case "mr":
															case "元空気溜め":
															case "元空気ダメ":
																NeedleType[k] = 5; break;
															default:
																{
																	int a; if (!Interface.TryParseIntVb6(Arguments[0], out a)) {
																		Interface.AddMessage(Interface.MessageType.Error, false, "Subject is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
																		a = 0;
																	}
																	NeedleType[k] = a;
																} break;
														}
													}
													int r = 0, g = 0, b = 0;
													if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseIntVb6(Arguments[1], out r)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "RedValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														r = 0;
													} else if (r < 0 | r > 255) {
														Interface.AddMessage(Interface.MessageType.Error, false, "RedValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														r = r < 0 ? 0 : 255;
													}
													if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Interface.TryParseIntVb6(Arguments[2], out g)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "GreenValue is invalid in " + Key + " in " + Section + Key + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														g = 0;
													} else if (g < 0 | g > 255) {
														Interface.AddMessage(Interface.MessageType.Error, false, "GreenValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														g = g < 0 ? 0 : 255;
													}
													if (Arguments.Length >= 4 && Arguments[3].Length > 0 && !Interface.TryParseIntVb6(Arguments[3], out b)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "BlueValue is invalid in " + Key + " in " + Section + Key + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														b = 0;
													} else if (b < 0 | b > 255) {
														Interface.AddMessage(Interface.MessageType.Error, false, "BlueValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														b = b < 0 ? 0 : 255;
													}
													NeedleColor[k] = new Color32((byte)r, (byte)g, (byte)b, 255);
													break;
												case "center":
												case "中心":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out CenterX)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CenterX = 0.0;
													} else if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[1], out CenterY)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CenterY = 0.0;
													} break;
												case "radius":
												case "半径":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Radius)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "ValueInPixels is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Radius = 1.0;
													} break;
												case "background":
												case "背景":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														Background = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(Background)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName " + Background + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Background = null;
														}
													}
													break;
												case "cover":
												case "ふた":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														Cover = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(Cover)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName " + Cover + "could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Cover = null;
														}
													}
													break;
												case "unit":
												case "単位":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0) {
														string a = Arguments[0].ToLowerInvariant();
														int Unit = 0;
														if (a == "kpa") {
															Unit = 0;
														} else if (a == "kgf/cm2" | a == "kgf/cm^2" | a == "kg/cm2" | a == "kg/cm^2") {
															Unit = 1;
														} else if (!Interface.TryParseIntVb6(Arguments[0], out Unit)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Unit = 0;
														} else if (Unit != 0 & Unit != 1) {
															Interface.AddMessage(Interface.MessageType.Error, false, "Value must be either 0 or 1 in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Unit = 0;
														}
														if (Unit == 1) {
															UnitFactor = 98066.5;
														} else {
															UnitFactor = 1000.0;
														}
													} break;
												case "maximum":
												case "最大":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Maximum)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "PressureValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Maximum = 1000.0;
													} break;
												case "minimum":
												case "最小":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Minimum)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "PressureValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Minimum = 0.0;
													} break;
												case "angle":
												case "角度":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Angle)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "ValueInDegrees is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Angle = 0.785398163397449;
													} else {
														Angle *= 0.0174532925199433;
													} break;
											}
										} i++;
									} i--;
									// units
									Minimum *= UnitFactor;
									Maximum *= UnitFactor;
									// background
									if (Background != null) {
										Textures.Texture t;
										Textures.RegisterTexture(Background, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										CreateElement(Train, CenterX - 0.5 * w, CenterY + SemiHeight - 0.5 * h, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 3.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
									}
									// cover
									if (Cover != null) {
										Textures.Texture t;
										Textures.RegisterTexture(Cover, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										CreateElement(Train, CenterX - 0.5 * w, CenterY + SemiHeight - 0.5 * h, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 6.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
									}
									if (Type == 0) {
										// needles
										for (int k = 0; k < 2; k++) {
											if (NeedleType[k] != 0) {
												string Folder = Program.FileSystem.GetDataFolder("Compatibility");
												string File = OpenBveApi.Path.CombineFile(Folder, k == 0 ? "needle_pressuregauge_lower.png" : "needle_pressuregauge_upper.png");
												Textures.Texture t;
												Textures.RegisterTexture(File, out t);
											    OpenBVEGame.RunInRenderThread(() =>
											    {
											        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
											    });
												double w = (double)t.Width;
												double h = (double)t.Height;
												int j = CreateElement(Train, CenterX - Radius * w / h, CenterY + SemiHeight - Radius, 2.0 * Radius * w / h, 2.0 * Radius, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - (double)(4 + k) * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, NeedleColor[k], false);
												Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection = new Vector3(0.0, 0.0, -1.0);
												Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection = new Vector3(1.0, 0.0, 0.0);
												Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateYDirection = Vector3.Cross(Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection, Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection);
												double c0 = (Angle * (Maximum - Minimum) - 2.0 * Minimum * Math.PI) / (Maximum - Minimum) + Math.PI;
												double c1 = 2.0 * (Math.PI - Angle) / (Maximum - Minimum);
												string Variable = "0";
												switch (NeedleType[k]) {
														case 1: Variable = "brakecylinder"; break;
														case 2: Variable = "straightairpipe"; break;
														case 3: Variable = "brakepipe"; break;
														case 4: Variable = "equalizingreservoir"; break;
														case 5: Variable = "mainreservoir"; break;
												}
												Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(Variable + " " + c1.ToString(Culture) + " " + c0.ToString(Culture) + " fma");
											}
										}
									} else if (Type == 1) {
										// leds
										if (NeedleType[1] != 0) {
											int j = CreateElement(Train, CenterX - Radius, CenterY + SemiHeight - Radius, 2.0 * Radius, 2.0 * Radius, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 5.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, null, NeedleColor[1], false);
											double x0 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[0].Coordinates.X;
											double y0 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[0].Coordinates.Y;
											double z0 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[0].Coordinates.Z;
											double x1 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[1].Coordinates.X;
											double y1 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[1].Coordinates.Y;
											double z1 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[1].Coordinates.Z;
											double x2 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[2].Coordinates.X;
											double y2 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[2].Coordinates.Y;
											double z2 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[2].Coordinates.Z;
											double x3 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[3].Coordinates.X;
											double y3 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[3].Coordinates.Y;
											double z3 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[3].Coordinates.Z;
											double cx = 0.25 * (x0 + x1 + x2 + x3);
											double cy = 0.25 * (y0 + y1 + y2 + y3);
											double cz = 0.25 * (z0 + z1 + z2 + z3);
											World.Vertex[] vertices = new World.Vertex[11];
											int[][] faces = new int[][] {
												new int[] { 0, 1, 2 },
												new int[] { 0, 3, 4 },
												new int[] { 0, 5, 6 },
												new int[] { 0, 7, 8 },
												new int[] { 0, 9, 10 }
											};
											Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh = new World.Mesh(vertices, faces, NeedleColor[1]);
											Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDClockwiseWinding = true;
											Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDInitialAngle = Angle - 2.0 * Math.PI;
											Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDLastAngle = 2.0 * Math.PI - Angle;
											Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDVectors = new Vector3[] {
												new Vector3(x0, y0, z0),
												new Vector3(x1, y1, z1),
												new Vector3(x2, y2, z2),
												new Vector3(x3, y3, z3),
												new Vector3(cx, cy, cz)
											};
											double c0 = (Angle * (Maximum - Minimum) - 2.0 * Minimum * Math.PI) / (Maximum - Minimum);
											double c1 = 2.0 * (Math.PI - Angle) / (Maximum - Minimum);
											string Variable;
											switch (NeedleType[1]) {
													case 1: Variable = "brakecylinder"; break;
													case 2: Variable = "straightairpipe"; break;
													case 3: Variable = "brakepipe"; break;
													case 4: Variable = "equalizingreservoir"; break;
													case 5: Variable = "mainreservoir"; break;
													default: Variable = "0"; break;
											}
											Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation(Variable + " " + c1.ToString(Culture) + " " + c0.ToString(Culture) + " fma");
										}
									}
								} break;
								// speedometer
							case "speedometer":
							case "speedindicator":
							case "速度計":
								{
									int Type = 0;
									Color32 Needle = new Color32(255, 255, 255, 255);
									bool NeedleOverridden = false;
									double CenterX = 0.0, CenterY = 0.0, Radius = 16.0;
									string Background = null, Cover = null, Atc = null;
									double Angle = 1.0471975511966, Maximum = 33.3333333333333, AtcRadius = 0.0;
									i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
										int j = Lines[i].IndexOf('='); if (j >= 0) {
											string Key = Lines[i].Substring(0, j).TrimEnd();
											string Value = Lines[i].Substring(j + 1).TrimStart();
											string[] Arguments = GetArguments(Value);
											switch (Key.ToLowerInvariant()) {
												case "type":
												case "形態":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseIntVb6(Arguments[0], out Type)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Type = 0;
													} else if (Type != 0 & Type != 1) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Value must be either 0 or 1 in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Type = 0;
													} break;
												case "background":
												case "背景":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														Background = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(Background)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName " + Background + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Background = null;
														}
													}
													break;
												case "needle":
												case "hand":
												case "針":
													{
														int r = 0, g = 0, b = 0;
														if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseIntVb6(Arguments[0], out r)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "RedValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															r = 255;
														} else if (r < 0 | r > 255) {
															Interface.AddMessage(Interface.MessageType.Error, false, "RedValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															r = r < 0 ? 0 : 255;
														}
														if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseIntVb6(Arguments[1], out g)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "GreenValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															g = 255;
														} else if (g < 0 | g > 255) {
															Interface.AddMessage(Interface.MessageType.Error, false, "GreenValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															g = g < 0 ? 0 : 255;
														}
														if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Interface.TryParseIntVb6(Arguments[2], out b)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "BlueValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															b = 255;
														} else if (b < 0 | b > 255) {
															Interface.AddMessage(Interface.MessageType.Error, false, "BlueValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															b = b < 0 ? 0 : 255;
														}
														Needle = new Color32((byte)r, (byte)g, (byte)b, 255);
														NeedleOverridden = true;
													} break;
												case "cover":
												case "ふた":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													Cover = OpenBveApi.Path.CombineFile(TrainPath, Value);
													if (!System.IO.File.Exists(Cover)) {
														Interface.AddMessage(Interface.MessageType.Error, true, "FileName" + Cover + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Cover = null;
													} break;
												case "atc":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													Atc = OpenBveApi.Path.CombineFile(TrainPath, Value);
													if (!System.IO.File.Exists(Atc)) {
														Interface.AddMessage(Interface.MessageType.Error, true, "FileName" + Atc + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Atc = null;
													} break;
												case "atcradius":
												case "atc半径":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out AtcRadius)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "ValueInPixels is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														AtcRadius = 0.0;
													} break;
												case "center":
												case "中心":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out CenterX)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CenterX = 0.0;
													} else if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[1], out CenterY)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CenterY = 0.0;
													} break;
												case "radius":
												case "半径":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Radius)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "ValueInPixels is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Radius = 0.0;
													} break;
												case "angle":
												case "角度":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Angle)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "ValueInDegrees is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Angle = 1.0471975511966;
													} else {
														Angle *= 0.0174532925199433;
													} break;
												case "maximum":
												case "最大":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Maximum)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "SpeedValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Maximum = 33.3333333333333;
													} else {
														Maximum *= 0.277777777777778;
													} break;
											}
										} i++;
									} i--;
									if (Background != null) {
										// background/led
										Textures.Texture t;
										Textures.RegisterTexture(Background, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										CreateElement(Train, CenterX - 0.5 * w, CenterY + SemiHeight - 0.5 * h, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 3.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
									}
									if (Cover != null) {
										// cover
										Textures.Texture t;
										Textures.RegisterTexture(Cover, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										CreateElement(Train, CenterX - 0.5 * w, CenterY + SemiHeight - 0.5 * h, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 6.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
									}
									if (Atc != null) {
										// atc
										int w, h;
										Program.CurrentHost.QueryTextureDimensions(Atc, out w, out h);
										if (w > 0 & h > 0) {
											int n = w / h;
											int k = -1;
											for (int j = 0; j < n; j++) {
												double s; switch (j) {
														case 1: s = 0.0; break;
														case 2: s = 15.0; break;
														case 3: s = 25.0; break;
														case 4: s = 45.0; break;
														case 5: s = 55.0; break;
														case 6: s = 65.0; break;
														case 7: s = 75.0; break;
														case 8: s = 90.0; break;
														case 9: s = 100.0; break;
														case 10: s = 110.0; break;
														case 11: s = 120.0; break;
														default: s = -1.0; break;
												} s *= 0.277777777777778;
												double a; if (s >= 0.0) {
													a = 2.0 * s * (Math.PI - Angle) / Maximum + Angle + Math.PI;
												} else {
													a = Math.PI;
												}
												double x = CenterX - 0.5 * h + Math.Sin(a) * AtcRadius;
												double y = CenterY - 0.5 * h - Math.Cos(a) * AtcRadius + SemiHeight;
												Textures.Texture t;
												Textures.RegisterTexture(Atc, new OpenBveApi.Textures.TextureParameters(new OpenBveApi.Textures.TextureClipRegion(j * h, 0, h, h), Color24.Blue), out t);
											    OpenBVEGame.RunInRenderThread(() =>
											    {
											        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
											    });
												if (j == 0) {
													k = CreateElement(Train, x, y, (double)h, (double)h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 4.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
												} else {
													CreateElement(Train, x, y, (double)h, (double)h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 4.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), true);
												}
											}
											Train.Cars[Train.DriverCar].CarSections[0].Elements[k].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("271 pluginstate");
										}
									}
									if (Type == 0) {
										// needle
										string Folder = Program.FileSystem.GetDataFolder("Compatibility");
										string File = OpenBveApi.Path.CombineFile(Folder, "needle_speedometer.png");
										Textures.Texture t;
										Textures.RegisterTexture(File, out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										int j = CreateElement(Train, CenterX - Radius * w / h, CenterY + SemiHeight - Radius, 2.0 * Radius * w / h, 2.0 * Radius, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 5.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, Needle, false);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection = new Vector3(0.0, 0.0, -1.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection = new Vector3(1.0, 0.0, 0.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateYDirection = Vector3.Cross(Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection, Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection);
										double c0 = Angle + Math.PI;
										double c1 = 2.0 * (Math.PI - Angle) / Maximum;
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("speedometer abs " + c1.ToString(Culture) + " " + c0.ToString(Culture) + " fma");
									} else if (Type == 1) {
										// led
										if (!NeedleOverridden) Needle = new Color32(0, 0, 0, 255);
										int j = CreateElement(Train, CenterX - Radius, CenterY + SemiHeight - Radius, 2.0 * Radius, 2.0 * Radius, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 5.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, null, Needle, false);
										double x0 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[0].Coordinates.X;
										double y0 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[0].Coordinates.Y;
										double z0 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[0].Coordinates.Z;
										double x1 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[1].Coordinates.X;
										double y1 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[1].Coordinates.Y;
										double z1 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[1].Coordinates.Z;
										double x2 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[2].Coordinates.X;
										double y2 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[2].Coordinates.Y;
										double z2 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[2].Coordinates.Z;
										double x3 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[3].Coordinates.X;
										double y3 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[3].Coordinates.Y;
										double z3 = Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh.Vertices[3].Coordinates.Z;
										double cx = 0.25 * (x0 + x1 + x2 + x3);
										double cy = 0.25 * (y0 + y1 + y2 + y3);
										double cz = 0.25 * (z0 + z1 + z2 + z3);
										World.Vertex[] vertices = new World.Vertex[11];
										int[][] faces = new int[][] {
											new int[] { 0, 1, 2 },
											new int[] { 0, 3, 4 },
											new int[] { 0, 5, 6 },
											new int[] { 0, 7, 8 },
											new int[] { 0, 9, 10 }
										};
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].States[0].Object.Mesh = new World.Mesh(vertices, faces, Needle);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDClockwiseWinding = true;
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDInitialAngle = Angle - 2.0 * Math.PI;
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDLastAngle = 2.0 * Math.PI - Angle;
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDVectors = new Vector3[] {
											new Vector3(x0, y0, z0),
											new Vector3(x1, y1, z1),
											new Vector3(x2, y2, z2),
											new Vector3(x3, y3, z3),
											new Vector3(cx, cy, cz)
										};
										double c0 = Angle;
										double c1 = 2.0 * (Math.PI - Angle) / Maximum;
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].LEDFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("speedometer abs " + c1.ToString(Culture) + " " + c0.ToString(Culture) + " fma");
									}
								} break;
								// digitalindicator
							case "digitalindicator":
								{
									string Number = null;
									double CornerX = 0.0, CornerY = 0.0;
									int Width = 0, Height = 0;
									double UnitFactor = 3.6;
									i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
										int j = Lines[i].IndexOf('='); if (j >= 0) {
											string Key = Lines[i].Substring(0, j).TrimEnd();
											string Value = Lines[i].Substring(j + 1).TrimStart();
											string[] Arguments = GetArguments(Value);
											switch (Key.ToLowerInvariant()) {
												case "number":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														Number = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(Number)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName " + Number + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Number = null;
														}
													}
													break;
												case "corner":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out CornerX)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Left is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CornerX = 0.0;
													} else if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[1], out CornerY)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Top is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CornerY = 0.0;
													} break;
												case "size":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseIntVb6(Arguments[0], out Width)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Width is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Width = 0;
													} else if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseIntVb6(Arguments[1], out Height)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Height is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Height = 0;
													} break;
												case "unit":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0) {
														string a = Arguments[0].ToLowerInvariant();
														int Unit = 0;
														if (a == "km/h") {
															Unit = 0;
														} else if (a == "mph") {
															Unit = 1;
														} else if (a == "m/s") {
															Unit = 2;
														} else if (!Interface.TryParseIntVb6(Arguments[0], out Unit)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Unit = 0;
														} else if (Unit < 0 | Unit > 2) {
															Interface.AddMessage(Interface.MessageType.Error, false, "Value must be between 0 and 2 in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Unit = 0;
														}
														if (Unit == 1) {
															UnitFactor = 2.2369362920544;
														} else if (Unit == 2) {
															UnitFactor = 1.0;
														} else {
															UnitFactor = 3.6;
														}
													} break;
											}
										} i++;
									} i--;
									if (Number == null) {
										Interface.AddMessage(Interface.MessageType.Error, false, "Number is required to be specified in " + Section + " in " + FileName);
									}
									if (Width <= 0) {
										Interface.AddMessage(Interface.MessageType.Error, false, "Width is required to be specified in " + Section + " in " + FileName);
									}
									if (Height <= 0) {
										Interface.AddMessage(Interface.MessageType.Error, false, "Height is required to be specified in " + Section + " in " + FileName);
									}
									if (Number != null & Width > 0 & Height > 0) {
										int w, h;
										Program.CurrentHost.QueryTextureDimensions(Number, out w, out h);
										if (w > 0 & h > 0) {
											//Generate an error message rather than crashing if the clip region is invalid
											if (Width > w)
											{
												Width = w;
												Interface.AddMessage(Interface.MessageType.Warning, false, "Clip region width was greater than the texture width " + Section + " in " + FileName);
											}
											if (Height > h)
											{
												Height = h;
												Interface.AddMessage(Interface.MessageType.Warning, false, "Clip region height was greater than the texture height " + Section + " in " + FileName);
											}
											int n = h / Height;
											Textures.Texture[] t = new Textures.Texture[n];
											for (int j = 0; j < n; j++) {
												Textures.RegisterTexture(Number, new OpenBveApi.Textures.TextureParameters(new OpenBveApi.Textures.TextureClipRegion(w - Width, j * Height, Width, Height), Color24.Blue), out t[j]);
												//TextureManager.UseTexture(t[j], TextureManager.UseMode.Normal);
											}
											{ // hundreds
												int k = -1;
												for (int j = 0; j < n; j++) {
													if (j == 0) {
														k = CreateElement(Train, CornerX, CornerY + SemiHeight, (double)Width, (double)Height, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 7.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t[j], new Color32(255, 255, 255, 255), false);
													} else {
														CreateElement(Train, CornerX, CornerY + SemiHeight, (double)Width, (double)Height, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 7.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t[j], new Color32(255, 255, 255, 255), true);
													}
												}
												Train.Cars[Train.DriverCar].CarSections[0].Elements[k].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("speedometer abs " + UnitFactor.ToString(Culture) + " * ~ 100 >= <> 100 quotient 10 mod 10 ?");
											}
											{ // tens
												int k = -1;
												for (int j = 0; j < n; j++) {
													if (j == 0) {
														k = CreateElement(Train, CornerX + (double)Width, CornerY + SemiHeight, (double)Width, (double)Height, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 7.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t[j], new Color32(255, 255, 255, 255), false);
													} else {
														CreateElement(Train, CornerX + (double)Width, CornerY + SemiHeight, (double)Width, (double)Height, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 7.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t[j], new Color32(255, 255, 255, 255), true);
													}
												}
												Train.Cars[Train.DriverCar].CarSections[0].Elements[k].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("speedometer abs " + UnitFactor.ToString(Culture) + " * ~ 10 >= <> 10 quotient 10 mod 10 ?");
											}
											{ // ones
												int k = -1;
												for (int j = 0; j < n; j++) {
													if (j == 0) {
														k = CreateElement(Train, CornerX + 2.0 * (double)Width, CornerY + SemiHeight, (double)Width, (double)Height, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 7.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t[j], new Color32(255, 255, 255, 255), false);
													} else {
														CreateElement(Train, CornerX + 2.0 * (double)Width, CornerY + SemiHeight, (double)Width, (double)Height, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 7.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t[j], new Color32(255, 255, 255, 255), true);
													}
												}
												Train.Cars[Train.DriverCar].CarSections[0].Elements[k].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("speedometer abs " + UnitFactor.ToString(Culture) + " * floor 10 mod");
											}
										}
									}
								} break;
								// pilotlamp
							case "pilotlamp":
							case "知らせ灯":
								{
									double CornerX = 0.0, CornerY = 0.0;
									string TurnOn = null, TurnOff = null;
									i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
										int j = Lines[i].IndexOf('='); if (j >= 0) {
											string Key = Lines[i].Substring(0, j).TrimEnd();
											string Value = Lines[i].Substring(j + 1).TrimStart();
											string[] Arguments = GetArguments(Value);
											switch (Key.ToLowerInvariant()) {
												case "turnon":
												case "点灯":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														TurnOn = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(TurnOn)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName" + TurnOn + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															TurnOn = null;
														}
													}
													break;
												case "turnoff":
												case "消灯":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														TurnOff = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(TurnOff)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName" + TurnOff + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															TurnOff = null;
														}
													}
													break;
												case "corner":
												case "左上":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out CornerX)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Left is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CornerX = 0.0;
													} else if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[1], out CornerY)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Top is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CornerY = 0.0;
													} break;
											}
										} i++;
									} i--;
									if (TurnOn != null & TurnOff != null) {
										Textures.Texture t0, t1;
										Textures.RegisterTexture(TurnOn, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t0);
										Textures.RegisterTexture(TurnOff, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t1);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t0, Textures.OpenGlTextureWrapMode.ClampClamp);
									        Textures.LoadTexture(t1, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t0.Width;
										double h = (double)t0.Height;
										int j = CreateElement(Train, CornerX, CornerY + SemiHeight, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 2.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t0, new Color32(255, 255, 255, 255), false);
										w = (double)t1.Width;
										h = (double)t1.Height;
										CreateElement(Train, CornerX, CornerY + SemiHeight, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 2.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t1, new Color32(255, 255, 255, 255), true);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("doors 0 !=");
									}
								} break;
								// watch
							case "watch":
							case "時計":
								{
									Color32 Needle = new Color32(0, 0, 0, 255);
									double CenterX = 0.0, CenterY = 0.0, Radius = 16.0;
									string Background = null;
									i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
										int j = Lines[i].IndexOf('='); if (j >= 0) {
											string Key = Lines[i].Substring(0, j).TrimEnd();
											string Value = Lines[i].Substring(j + 1).TrimStart();
											string[] Arguments = GetArguments(Value);
											switch (Key.ToLowerInvariant()) {
												case "background":
												case "背景":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														Background = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(Background)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName" + Background + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Background = null;
														}
													}
													break;
												case "needle":
												case "hand":
												case "針":
													{
														int r = 0, g = 0, b = 0;
														if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseIntVb6(Arguments[0], out r)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "RedValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															r = 0;
														} else if (r < 0 | r > 255) {
															Interface.AddMessage(Interface.MessageType.Error, false, "RedValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															r = r < 0 ? 0 : 255;
														}
														if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseIntVb6(Arguments[1], out g)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "GreenValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															g = 0;
														} else if (g < 0 | g > 255) {
															Interface.AddMessage(Interface.MessageType.Error, false, "GreenValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															g = g < 0 ? 0 : 255;
														}
														if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !Interface.TryParseIntVb6(Arguments[2], out b)) {
															Interface.AddMessage(Interface.MessageType.Error, false, "BlueValue is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															b = 0;
														} else if (b < 0 | b > 255) {
															Interface.AddMessage(Interface.MessageType.Error, false, "BlueValue is required to be within the range from 0 to 255 in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															b = b < 0 ? 0 : 255;
														}
														Needle = new Color32((byte)r, (byte)g, (byte)b, 255);
													} break;
												case "center":
												case "中心":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out CenterX)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "X is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CenterX = 0.0;
													} else if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[1], out CenterY)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Y is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CenterY = 0.0;
													} break;
												case "radius":
												case "半径":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out Radius)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Radius = 16.0;
													} break;
											}
										} i++;
									} i--;
									if (Background != null) {
										Textures.Texture t;
										Textures.RegisterTexture(Background, new OpenBveApi.Textures.TextureParameters(null, Color24.Blue), out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										CreateElement(Train, CenterX - 0.5 * w, CenterY + SemiHeight - 0.5 * h, w, h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 3.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
									}
									string Folder = Program.FileSystem.GetDataFolder("Compatibility");
									{ // hour
										string File = OpenBveApi.Path.CombineFile(Folder, "needle_hour.png");
										Textures.Texture t;
										Textures.RegisterTexture(File, out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										int j = CreateElement(Train, CenterX - Radius * w / h, CenterY + SemiHeight - Radius, 2.0 * Radius * w / h, 2.0 * Radius, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 4.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, Needle, false);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection = new Vector3(0.0, 0.0, -1.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection = new Vector3(1.0, 0.0, 0.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateYDirection = Vector3.Cross(Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection, Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("time 0.000277777777777778 * floor 0.523598775598298 *");
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDamping = new ObjectManager.Damping(20.0, 0.4);
									}
									{ // minute
										string File = OpenBveApi.Path.CombineFile(Folder, "needle_minute.png");
										Textures.Texture t;
										Textures.RegisterTexture(File, out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										int j = CreateElement(Train, CenterX - Radius * w / h, CenterY + SemiHeight - Radius, 2.0 * Radius * w / h, 2.0 * Radius, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 5.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, Needle, false);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection = new Vector3(0.0, 0.0, -1.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection = new Vector3(1.0, 0.0, 0.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateYDirection = Vector3.Cross(Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection, Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("time 0.0166666666666667 * floor 0.10471975511966 *");
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDamping = new ObjectManager.Damping(20.0, 0.4);
									}
									{ // second
										string File = OpenBveApi.Path.CombineFile(Folder, "needle_second.png");
										Textures.Texture t;
										Textures.RegisterTexture(File, out t);
									    OpenBVEGame.RunInRenderThread(() =>
									    {
									        Textures.LoadTexture(t, Textures.OpenGlTextureWrapMode.ClampClamp);
									    });
										double w = (double)t.Width;
										double h = (double)t.Height;
										int j = CreateElement(Train, CenterX - Radius * w / h, CenterY + SemiHeight - Radius, 2.0 * Radius * w / h, 2.0 * Radius, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - 6.0 * StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, Needle, false);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection = new Vector3(0.0, 0.0, -1.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection = new Vector3(1.0, 0.0, 0.0);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateYDirection = Vector3.Cross(Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDirection, Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateXDirection);
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("time floor 0.10471975511966 *");
										Train.Cars[Train.DriverCar].CarSections[0].Elements[j].RotateZDamping = new ObjectManager.Damping(20.0, 0.4);
									}
								} break;
								// brakeindicator
							case "brakeindicator":
								{
									double CornerX = 0.0, CornerY = 0.0;
									string Image = null;
									int Width = 0;
									i++; while (i < Lines.Length && !(Lines[i].StartsWith("[", StringComparison.Ordinal) & Lines[i].EndsWith("]", StringComparison.Ordinal))) {
										int j = Lines[i].IndexOf('='); if (j >= 0) {
											string Key = Lines[i].Substring(0, j).TrimEnd();
											string Value = Lines[i].Substring(j + 1).TrimStart();
											string[] Arguments = GetArguments(Value);
											switch (Key.ToLowerInvariant()) {
												case "image":
													if (!System.IO.Path.HasExtension(Value)) Value += ".bmp";
													if (Interface.ContainsInvalidPathChars(Value)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "FileName contains illegal characters in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
													} else {
														Image = OpenBveApi.Path.CombineFile(TrainPath, Value);
														if (!System.IO.File.Exists(Image)) {
															Interface.AddMessage(Interface.MessageType.Error, true, "FileName " + Image + " could not be found in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
															Image = null;
														}
													}
													break;
												case "corner":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[0], out CornerX)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Left is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CornerX = 0.0;
													} else if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !Interface.TryParseDoubleVb6(Arguments[1], out CornerY)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Top is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														CornerY = 0.0;
													} break;
												case "width":
													if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !Interface.TryParseIntVb6(Arguments[0], out Width)) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Width is invalid in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Width = 1;
													} else if (Width <= 0) {
														Interface.AddMessage(Interface.MessageType.Error, false, "Width is expected to be positive in " + Key + " in " + Section + " at line " + (i + 1).ToString(Culture) + " in " + FileName);
														Width = 1;
													} break;
											}
										} i++;
									} i--;
									if (Image == null) {
										Interface.AddMessage(Interface.MessageType.Error, false, "Image is required to be specified in " + Section + " in " + FileName);
									}
									if (Width <= 0) {
										Interface.AddMessage(Interface.MessageType.Error, false, "Width is required to be specified in " + Section + " in " + FileName);
									}
									if (Image != null & Width > 0) {
										int w, h;
										Program.CurrentHost.QueryTextureDimensions(Image, out w, out h);
										if (w > 0 & h > 0) {
											int n = w / Width;
											int k = -1;
											for (int j = 0; j < n; j++) {
												Textures.Texture t;
												OpenBveApi.Textures.TextureClipRegion clip = new OpenBveApi.Textures.TextureClipRegion(j * Width, 0, Width, h);
												Textures.RegisterTexture(Image, new OpenBveApi.Textures.TextureParameters(clip, Color24.Blue), out t);
												//TextureManager.UseTexture(t, TextureManager.UseMode.Normal);
												if (j == 0) {
													k = CreateElement(Train, CornerX, CornerY + SemiHeight, (double)Width, (double)h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), false);
												} else {
													CreateElement(Train, CornerX, CornerY + SemiHeight, (double)Width, (double)h, FullWidth, FullHeight, WorldLeft, WorldTop, WorldWidth, WorldHeight, WorldZ + EyeDistance - StackDistance, Train.Cars[Train.DriverCar].DriverX, Train.Cars[Train.DriverCar].DriverY, Train.Cars[Train.DriverCar].DriverZ, t, new Color32(255, 255, 255, 255), true);
												}
											}
											if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) {
												int maxpow = Train.Specs.MaximumPowerNotch;
												int em = maxpow + 3;
												Train.Cars[Train.DriverCar].CarSections[0].Elements[k].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("emergencyBrake " + em.ToString(Culture) + " brakeNotch 0 > " + maxpow.ToString(Culture) + " BrakeNotch + " + maxpow.ToString(Culture) + " powerNotch - ? ?");
											} else {
												if (Train.Specs.HasHoldBrake) {
													int em = Train.Specs.MaximumPowerNotch + 2 + Train.Specs.MaximumBrakeNotch;
													int maxpow = Train.Specs.MaximumPowerNotch;
													int maxpowp1 = maxpow + 1;
													Train.Cars[Train.DriverCar].CarSections[0].Elements[k].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("emergencyBrake " + em.ToString(Culture) + " holdBrake " + maxpowp1.ToString(Culture) + " brakeNotch 0 > brakeNotch " + maxpowp1.ToString(Culture) + " + " + maxpow.ToString(Culture) + " powerNotch - ? ? ?");
												} else {
													int em = Train.Specs.MaximumPowerNotch + 1 + Train.Specs.MaximumBrakeNotch;
													int maxpow = Train.Specs.MaximumPowerNotch;
													Train.Cars[Train.DriverCar].CarSections[0].Elements[k].StateFunction = FunctionScripts.GetFunctionScriptFromPostfixNotation("emergencyBrake " + em.ToString(Culture) + " brakeNotch 0 > brakeNotch " + maxpow.ToString(Culture) + " + " + maxpow.ToString(Culture) + " powerNotch - ? ?");
												}
											}
										}
									}
								} break;
						}
					}
				}
			}
		}
Пример #52
0
        /// <summary>This method is called once the route and train data have been preprocessed, in order to physically setup the simulation</summary>
        private void SetupSimulation()
        {
            if (Loading.Cancel)
            {
                Close();
            }
            Timetable.CreateTimetable();
            //Check if any critical errors have occured during the route or train loading
            for (int i = 0; i < Interface.MessageCount; i++)
            {
                if (Interface.Messages[i].Type == Interface.MessageType.Critical)
                {
                    MessageBox.Show("A critical error has occured:\n\n" + Interface.Messages[i].Text + "\n\nPlease inspect the error log file for further information.", "Load", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    Close();
                }
            }
            Renderer.InitializeLighting();
            Game.LogRouteName = System.IO.Path.GetFileName(MainLoop.currentResult.RouteFile);
            Game.LogTrainName = System.IO.Path.GetFileName(MainLoop.currentResult.TrainFolder);
            Game.LogDateTime  = DateTime.Now;

            if (Interface.CurrentOptions.LoadInAdvance)
            {
                Textures.LoadAllTextures();
            }
            else
            {
                Textures.UnloadAllTextures();
            }
            // camera
            ObjectManager.InitializeVisibility();
            TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, 0.0, true, false);
            TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, -0.1, true, false);
            TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, 0.1, true, false);
            World.CameraTrackFollower.TriggerType = TrackManager.EventTriggerType.Camera;
            // starting time and track position
            Game.SecondsSinceMidnight = 0.0;
            Game.StartupTime          = 0.0;
            int    PlayerFirstStationIndex    = -1;
            double PlayerFirstStationPosition = 0.0;

            for (int i = 0; i < Game.Stations.Length; i++)
            {
                if (Game.Stations[i].StopMode == Game.StationStopMode.AllStop | Game.Stations[i].StopMode == Game.StationStopMode.PlayerStop & Game.Stations[i].Stops.Length != 0)
                {
                    PlayerFirstStationIndex = i;
                    int s = Game.GetStopIndex(i, TrainManager.PlayerTrain.Cars.Length);
                    if (s >= 0)
                    {
                        PlayerFirstStationPosition = Game.Stations[i].Stops[s].TrackPosition;

                        double TrainLength = 0.0;
                        for (int c = 0; c < TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars.Length; c++)
                        {
                            TrainLength += TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars[c].Length;
                        }

                        for (int j = 0; j < Game.BufferTrackPositions.Length; j++)
                        {
                            if (PlayerFirstStationPosition > Game.BufferTrackPositions[j] && PlayerFirstStationPosition - TrainLength < Game.BufferTrackPositions[j])
                            {
                                /*
                                 * HACK: The initial start position for the player train is stuck on a set of buffers
                                 * This means we have to make some one the fly adjustments to the first station stop position
                                 */

                                //Set the start position to be the buffer position plus the train length plus 1m
                                PlayerFirstStationPosition = Game.BufferTrackPositions[j] + TrainLength + 1;
                                //Update the station stop location
                                if (s >= 0)
                                {
                                    Game.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition = PlayerFirstStationPosition;
                                }
                                else
                                {
                                    Game.Stations[PlayerFirstStationIndex].DefaultTrackPosition = PlayerFirstStationPosition;
                                }
                                break;
                            }
                        }
                    }
                    else
                    {
                        PlayerFirstStationPosition = Game.Stations[i].DefaultTrackPosition;
                    }
                    if (Game.Stations[i].ArrivalTime < 0.0)
                    {
                        if (Game.Stations[i].DepartureTime < 0.0)
                        {
                            Game.SecondsSinceMidnight = 0.0;
                            Game.StartupTime          = 0.0;
                        }
                        else
                        {
                            Game.SecondsSinceMidnight = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime;
                            Game.StartupTime          = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime;
                        }
                    }
                    else
                    {
                        Game.SecondsSinceMidnight = Game.Stations[i].ArrivalTime;
                        Game.StartupTime          = Game.Stations[i].ArrivalTime;
                    }
                    break;
                }
            }
            int    OtherFirstStationIndex    = -1;
            double OtherFirstStationPosition = 0.0;
            double OtherFirstStationTime     = 0.0;

            for (int i = 0; i < Game.Stations.Length; i++)
            {
                if (Game.Stations[i].StopMode == Game.StationStopMode.AllStop | Game.Stations[i].StopMode == Game.StationStopMode.PlayerPass & Game.Stations[i].Stops.Length != 0)
                {
                    OtherFirstStationIndex = i;
                    int s = Game.GetStopIndex(i, TrainManager.PlayerTrain.Cars.Length);
                    if (s >= 0)
                    {
                        OtherFirstStationPosition = Game.Stations[i].Stops[s].TrackPosition;
                    }
                    else
                    {
                        OtherFirstStationPosition = Game.Stations[i].DefaultTrackPosition;
                    }
                    if (Game.Stations[i].ArrivalTime < 0.0)
                    {
                        if (Game.Stations[i].DepartureTime < 0.0)
                        {
                            OtherFirstStationTime = 0.0;
                        }
                        else
                        {
                            OtherFirstStationTime = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime;
                        }
                    }
                    else
                    {
                        OtherFirstStationTime = Game.Stations[i].ArrivalTime;
                    }
                    break;
                }
            }
            if (Game.PrecedingTrainTimeDeltas.Length != 0)
            {
                OtherFirstStationTime -= Game.PrecedingTrainTimeDeltas[Game.PrecedingTrainTimeDeltas.Length - 1];
                if (OtherFirstStationTime < Game.SecondsSinceMidnight)
                {
                    Game.SecondsSinceMidnight = OtherFirstStationTime;
                }
            }
            // initialize trains
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                TrainManager.InitializeTrain(TrainManager.Trains[i]);
                int s = i == TrainManager.PlayerTrain.TrainIndex ? PlayerFirstStationIndex : OtherFirstStationIndex;
                if (s >= 0)
                {
                    if (Game.Stations[s].OpenLeftDoors)
                    {
                        for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                        {
                            TrainManager.Trains[i].Cars[j].Specs.AnticipatedLeftDoorsOpened = true;
                        }
                    }
                    if (Game.Stations[s].OpenRightDoors)
                    {
                        for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                        {
                            TrainManager.Trains[i].Cars[j].Specs.AnticipatedRightDoorsOpened = true;
                        }
                    }
                }
                if (Game.Sections.Length != 0)
                {
                    Game.Sections[0].Enter(TrainManager.Trains[i]);
                }
                for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                {
                    double length = TrainManager.Trains[i].Cars[0].Length;
                    TrainManager.MoveCar(TrainManager.Trains[i], j, -length, 0.01);
                    TrainManager.MoveCar(TrainManager.Trains[i], j, length, 0.01);
                }
            }
            // score
            Game.CurrentScore.ArrivalStation   = PlayerFirstStationIndex + 1;
            Game.CurrentScore.DepartureStation = PlayerFirstStationIndex;
            Game.CurrentScore.Maximum          = 0;
            for (int i = 0; i < Game.Stations.Length; i++)
            {
                if (i != PlayerFirstStationIndex & Game.PlayerStopsAtStation(i))
                {
                    if (i == 0 || Game.Stations[i - 1].StationType != Game.StationType.ChangeEnds)
                    {
                        Game.CurrentScore.Maximum += Game.ScoreValueStationArrival;
                    }
                }
            }
            if (Game.CurrentScore.Maximum <= 0)
            {
                Game.CurrentScore.Maximum = Game.ScoreValueStationArrival;
            }
            // signals
            if (Game.Sections.Length > 0)
            {
                Game.UpdateSection(Game.Sections.Length - 1);
            }
            // move train in position
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                double p;
                if (i == TrainManager.PlayerTrain.TrainIndex)
                {
                    p = PlayerFirstStationPosition;
                }
                else if (TrainManager.Trains[i].State == TrainManager.TrainState.Bogus)
                {
                    p = Game.BogusPretrainInstructions[0].TrackPosition;
                    TrainManager.Trains[i].AI = new Game.BogusPretrainAI(TrainManager.Trains[i]);
                }
                else
                {
                    p = OtherFirstStationPosition;
                }
                for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++)
                {
                    TrainManager.MoveCar(TrainManager.Trains[i], j, p, 0.01);
                }
            }
            // timetable
            if (Timetable.DefaultTimetableDescription.Length == 0)
            {
                Timetable.DefaultTimetableDescription = Game.LogTrainName;
            }

            // initialize camera
            if (World.CameraRestriction == World.CameraRestrictionMode.NotAvailable)
            {
                World.CameraMode = World.CameraViewMode.InteriorLookAhead;
            }
            //Place the initial camera in the driver car
            TrainManager.UpdateCamera(TrainManager.PlayerTrain, TrainManager.PlayerTrain.DriverCar);
            TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, -1.0, true, false);
            ObjectManager.UpdateVisibility(World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z);
            World.CameraSavedInterior = new World.CameraAlignment();
            World.CameraSavedExterior = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-2.5, 1.5, -15.0), 0.3, -0.2, 0.0, PlayerFirstStationPosition, 1.0);
            World.CameraSavedTrack    = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-3.0, 2.5, 0.0), 0.3, 0.0, 0.0, TrainManager.PlayerTrain.Cars[0].FrontAxle.Follower.TrackPosition - 10.0, 1.0);
            // signalling sections
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                int s = TrainManager.Trains[i].CurrentSectionIndex;
                Game.Sections[s].Enter(TrainManager.Trains[i]);
            }
            if (Game.Sections.Length > 0)
            {
                Game.UpdateSection(Game.Sections.Length - 1);
            }
            // fast-forward until start time
            {
                Game.MinimalisticSimulation = true;
                const double w = 0.25;
                double       u = Game.StartupTime - Game.SecondsSinceMidnight;
                if (u > 0)
                {
                    while (true)
                    {
                        double v = u < w ? u : w; u -= v;
                        Game.SecondsSinceMidnight += v;
                        TrainManager.UpdateTrains(v);
                        if (u <= 0.0)
                        {
                            break;
                        }
                        TotalTimeElapsedForSectionUpdate += v;
                        if (TotalTimeElapsedForSectionUpdate >= 1.0)
                        {
                            if (Game.Sections.Length > 0)
                            {
                                Game.UpdateSection(Game.Sections.Length - 1);
                            }
                            TotalTimeElapsedForSectionUpdate = 0.0;
                        }
                    }
                }
                Game.MinimalisticSimulation = false;
            }
            // animated objects
            ObjectManager.UpdateAnimatedWorldObjects(0.0, true);
            TrainManager.UpdateTrainObjects(0.0, true);
            // timetable
            if (TrainManager.PlayerTrain.Station >= 0)
            {
                Timetable.UpdateCustomTimetable(Game.Stations[TrainManager.PlayerTrain.Station].TimetableDaytimeTexture, Game.Stations[TrainManager.PlayerTrain.Station].TimetableNighttimeTexture);
                if (Timetable.CustomObjectsUsed != 0 & Timetable.CustomTimetableAvailable && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.AutoGenerated && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.None)
                {
                    Timetable.CurrentTimetable = Timetable.TimetableState.Custom;
                }
            }

            // warnings / errors
            if (Interface.MessageCount != 0)
            {
                int filesNotFound = 0;
                int errors        = 0;
                int warnings      = 0;
                for (int i = 0; i < Interface.MessageCount; i++)
                {
                    if (Interface.Messages[i].FileNotFound)
                    {
                        filesNotFound++;
                    }
                    else if (Interface.Messages[i].Type == Interface.MessageType.Error)
                    {
                        errors++;
                    }
                    else if (Interface.Messages[i].Type == Interface.MessageType.Warning)
                    {
                        warnings++;
                    }
                }
                string NotFound = null;
                string Messages = null;
                if (filesNotFound != 0)
                {
                    NotFound = filesNotFound.ToString() + " file(s) not found";
                    Game.AddDebugMessage(NotFound, 10.0);
                }
                if (errors != 0 & warnings != 0)
                {
                    Messages = errors.ToString() + " error(s), " + warnings.ToString() + " warning(s)";
                    Game.AddDebugMessage(Messages, 10.0);
                }
                else if (errors != 0)
                {
                    Messages = errors.ToString() + " error(s)";
                    Game.AddDebugMessage(Messages, 10.0);
                }
                else
                {
                    Messages = warnings.ToString() + " warning(s)";
                    Game.AddDebugMessage(Messages, 10.0);
                }
                Game.RouteInformation.FilesNotFound     = NotFound;
                Game.RouteInformation.ErrorsAndWarnings = Messages;
                //Print the plugin error encountered (If any) for 10s
                //This must be done after the simulation has init, as otherwise the timeout doesn't work
                if (Loading.PluginError != null)
                {
                    Game.AddMessage(Loading.PluginError, Game.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0);
                    Game.AddMessage(Interface.GetInterfaceString("errors_plugin_failure2"), Game.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0);
                }
            }
            loadComplete          = true;
            RenderRealTimeElapsed = 0.0;
            RenderTimeElapsed     = 0.0;
            World.InitializeCameraRestriction();
        }
Пример #53
0
		/// <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)) {
				Interface.AddMessage(Interface.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) {
				Interface.AddMessage(Interface.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) {
						Interface.AddMessage(Interface.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;
						} else {
							train.Plugin = null;
							return false;
						}
					}
				}
				Interface.AddMessage(Interface.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)) {
					Interface.AddMessage(Interface.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) {
				Interface.AddMessage(Interface.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) {
				Interface.AddMessage(Interface.MessageType.Warning, false, "The train plugin " + pluginTitle + " can only be used on 32-bit Microsoft Windows or compatible.");
				return false;
			}
		    if (Program.CurrentlyRunningOnWindows && !System.IO.File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\AtsPluginProxy.dll"))
		    {
                Interface.AddMessage(Interface.MessageType.Warning, false, "AtsPluginProxy.dll is missing or corrupt- Please reinstall.");
		        return false;
		    }
			train.Plugin = new Win32Plugin(pluginFile, train);
			if (train.Plugin.Load(specs, mode)) {
				return true;
			} else {
				train.Plugin = null;
				Interface.AddMessage(Interface.MessageType.Error, false, "The train plugin " + pluginTitle + " does not export a train interface and therefore cannot be used with openBVE.");
				return false;
			}
		}
Пример #54
0
        /// <summary>Updates the sound component. Should be called every frame.</summary>
        /// <param name="timeElapsed">The time in seconds that elapsed since the last call to this function.</param>
        private static void UpdateLinearModel(double timeElapsed)
        {
            /*
             * Set up the listener
             * */
            OpenBveApi.Math.Vector3D     listenerPosition    = World.AbsoluteCameraPosition;
            OpenBveApi.Math.Orientation3 listenerOrientation = new OpenBveApi.Math.Orientation3(World.AbsoluteCameraSide, World.AbsoluteCameraUp, World.AbsoluteCameraDirection);
            OpenBveApi.Math.Vector3D     listenerVelocity;
            if (World.CameraMode == World.CameraViewMode.Interior || World.CameraMode == World.CameraViewMode.InteriorLookAhead || World.CameraMode == World.CameraViewMode.Exterior)
            {
                TrainManager.Car         car  = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar];
                OpenBveApi.Math.Vector3D diff = car.FrontAxle.Follower.WorldPosition - car.RearAxle.Follower.WorldPosition;
                listenerVelocity = car.Specs.CurrentSpeed * OpenBveApi.Math.Vector3D.Normalize(diff) + World.CameraAlignmentSpeed.Position;
            }
            else
            {
                listenerVelocity = World.CameraAlignmentSpeed.Position;
            }
            float[] vectors =
            {
                (float)listenerOrientation.Z.X,
                (float)listenerOrientation.Z.Y,
                (float)listenerOrientation.Z.Z,
                -(float)listenerOrientation.Y.X,
                -(float)listenerOrientation.Y.Y,
                -(float)listenerOrientation.Y.Z
            };
            AL.Listener(ALListener3f.Position, 0.0f, 0.0f, 0.0f);
            AL.Listener(ALListener3f.Velocity, (float)listenerVelocity.X, (float)listenerVelocity.Y, (float)listenerVelocity.Z);
            AL.Listener(ALListenerfv.Orientation, ref vectors);

            /*
             * Set up the atmospheric attributes
             * */
            double elevation      = World.AbsoluteCameraPosition.Y + Game.RouteInitialElevation;
            double airTemperature = Game.GetAirTemperature(elevation);
            double airPressure    = Game.GetAirPressure(elevation, airTemperature);
            // double airDensity = Game.GetAirDensity(airPressure, airTemperature);
            double speedOfSound = Game.GetSpeedOfSound(airPressure, airTemperature);

            try {
                AL.SpeedOfSound((float)speedOfSound);
            } catch { }

            /*
             * Update the sound sources
             * */
            int actuallyPlaying = 0;

            for (int i = 0; i < SourceCount; i++)
            {
                if (Sources[i].State == SoundSourceState.StopPending)
                {
                    /*
                     * The sound is still playing but is to be stopped.
                     * Stop the sound, then remove it from the list of
                     * sound sources.
                     * */
                    AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                    Sources[i].State            = SoundSourceState.Stopped;
                    Sources[i].OpenAlSourceName = 0;
                    Sources[i] = Sources[SourceCount - 1];
                    SourceCount--;
                    i--;
                }
                else if (Sources[i].State == SoundSourceState.Stopped)
                {
                    /*
                     * The sound was already stopped. Remove it from
                     * the list of sound sources.
                     * */
                    Sources[i] = Sources[SourceCount - 1];
                    SourceCount--;
                    i--;
                }
                else if (GlobalMute)
                {
                    /*
                     * The sound is playing or about to be played, but
                     * the global mute option is enabled. Stop the sound
                     * sound if necessary, then remove it from the list
                     * of sound sources if the sound is not looping.
                     * */
                    if (Sources[i].State == SoundSourceState.Playing)
                    {
                        AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                        Sources[i].State            = SoundSourceState.PlayPending;
                        Sources[i].OpenAlSourceName = 0;
                    }
                    if (!Sources[i].Looped)
                    {
                        Sources[i].State            = SoundSourceState.Stopped;
                        Sources[i].OpenAlSourceName = 0;
                        Sources[i] = Sources[SourceCount - 1];
                        SourceCount--;
                        i--;
                    }
                }
                else
                {
                    /*
                     * The sound is to be played or is already playing.
                     * Calculate the sound gain.
                     * */
                    OpenBveApi.Math.Vector3D position;
                    OpenBveApi.Math.Vector3D velocity;
                    if (Sources[i].Train != null)
                    {
                        OpenBveApi.Math.Vector3D direction;
                        TrainManager.CreateWorldCoordinates(Sources[i].Train, Sources[i].Car, Sources[i].Position.X, Sources[i].Position.Y, Sources[i].Position.Z, out position.X, out position.Y, out position.Z, out direction.X, out direction.Y, out direction.Z);
                        velocity = Sources[i].Train.Cars[Sources[i].Car].Specs.CurrentSpeed * direction;
                    }
                    else
                    {
                        position = Sources[i].Position;
                        velocity = OpenBveApi.Math.Vector3D.Null;
                    }
                    OpenBveApi.Math.Vector3D positionDifference = position - listenerPosition;
                    double gain;
                    if (GlobalMute)
                    {
                        gain = 0.0;
                    }
                    else
                    {
                        double distance    = positionDifference.Norm();
                        double innerRadius = Sources[i].Radius;
                        if (World.CameraMode == World.CameraViewMode.Interior || World.CameraMode == World.CameraViewMode.InteriorLookAhead)
                        {
                            if (Sources[i].Train != TrainManager.PlayerTrain || Sources[i].Car != TrainManager.PlayerTrain.DriverCar)
                            {
                                innerRadius *= 0.5;
                            }
                        }
                        double outerRadius = OuterRadiusFactor * innerRadius;
                        if (distance < outerRadius)
                        {
                            if (distance <= innerRadius)
                            {
                                gain = Sources[i].Volume;
                            }
                            else
                            {
                                gain  = (distance - outerRadius) / (innerRadius - outerRadius);
                                gain *= Sources[i].Volume;
                            }
                            gain = 3.0 * gain * gain - 2.0 * gain * gain * gain;
                        }
                        else
                        {
                            gain = 0.0;
                        }
                    }
                    if (gain <= GainThreshold)
                    {
                        /*
                         * If the gain is too low to be audible, stop the sound.
                         * If the sound is not looping, stop it if necessary,
                         * then remove it from the list of sound sources.
                         * */
                        if (Sources[i].State == SoundSourceState.Playing)
                        {
                            AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                            Sources[i].State            = SoundSourceState.PlayPending;
                            Sources[i].OpenAlSourceName = 0;
                        }
                        if (!Sources[i].Looped)
                        {
                            Sources[i].State            = SoundSourceState.Stopped;
                            Sources[i].OpenAlSourceName = 0;
                            Sources[i] = Sources[SourceCount - 1];
                            SourceCount--;
                            i--;
                        }
                    }
                    else
                    {
                        /*
                         * Play the sound and update position, velocity, pitch and gain.
                         * For non-looping sounds, check if the sound is still playing.
                         * */
                        gain = (gain - GainThreshold) / (1.0 - GainThreshold);
                        if (Sources[i].State != SoundSourceState.Playing)
                        {
                            LoadBuffer(Sources[i].Buffer);
                            if (Sources[i].Buffer.Loaded)
                            {
                                AL.GenSources(1, out Sources[i].OpenAlSourceName);
                                AL.Source(Sources[i].OpenAlSourceName, ALSourcei.Buffer, Sources[i].Buffer.OpenAlBufferName);
                            }
                            else
                            {
                                /*
                                 * We cannot play the sound because
                                 * the buffer could not be loaded.
                                 * */
                                Sources[i].State = SoundSourceState.Stopped;
                                continue;
                            }
                        }
                        AL.Source(Sources[i].OpenAlSourceName, ALSource3f.Position, (float)positionDifference.X, (float)positionDifference.Y, (float)positionDifference.Z);
                        AL.Source(Sources[i].OpenAlSourceName, ALSource3f.Velocity, (float)velocity.X, (float)velocity.Y, (float)velocity.Z);
                        AL.Source(Sources[i].OpenAlSourceName, ALSourcef.Pitch, (float)Sources[i].Pitch);
                        AL.Source(Sources[i].OpenAlSourceName, ALSourcef.Gain, (float)gain);
                        if (Sources[i].State != SoundSourceState.Playing)
                        {
                            AL.Source(Sources[i].OpenAlSourceName, ALSourceb.Looping, Sources[i].Looped);
                            AL.SourcePlay(Sources[i].OpenAlSourceName);
                            Sources[i].State = SoundSourceState.Playing;
                        }
                        if (!Sources[i].Looped)
                        {
                            int state;
                            AL.GetSource(Sources[i].OpenAlSourceName, ALGetSourcei.SourceState, out state);
                            if (state != (int)ALSourceState.Initial && state != (int)ALSourceState.Playing)
                            {
                                /*
                                 * The sound is not playing any longer.
                                 * Remove it from the list of sound sources.
                                 * */
                                AL.DeleteSources(1, ref Sources[i].OpenAlSourceName);
                                Sources[i].State            = SoundSourceState.Stopped;
                                Sources[i].OpenAlSourceName = 0;
                                Sources[i] = Sources[SourceCount - 1];
                                SourceCount--;
                                i--;
                            }
                            else
                            {
                                actuallyPlaying++;
                            }
                        }
                        else
                        {
                            actuallyPlaying++;
                        }
                    }
                }
            }

            /*
             * Adjust the outer radius factor / the clamp factor.
             * */
            if (actuallyPlaying >= Options.Current.SoundNumber - 2)
            {
                /*
                 * Too many sounds are playing.
                 * Reduce the outer radius factor.
                 * */
                OuterRadiusFactorSpeed -= timeElapsed;
                if (OuterRadiusFactorSpeed < -OuterRadiusFactorMaximumSpeed)
                {
                    OuterRadiusFactorSpeed = -OuterRadiusFactorMaximumSpeed;
                }
            }
            else if (actuallyPlaying <= Options.Current.SoundNumber - 6)
            {
                /*
                 * Only few sounds are playing.
                 * Increase the outer radius factor.
                 * */
                OuterRadiusFactorSpeed += timeElapsed;
                if (OuterRadiusFactorSpeed > OuterRadiusFactorMaximumSpeed)
                {
                    OuterRadiusFactorSpeed = OuterRadiusFactorMaximumSpeed;
                }
            }
            else
            {
                /*
                 * Neither too many nor too few sounds are playing.
                 * Stabilize the outer radius factor.
                 * */
                if (OuterRadiusFactorSpeed < 0.0)
                {
                    OuterRadiusFactorSpeed += timeElapsed;
                    if (OuterRadiusFactorSpeed > 0.0)
                    {
                        OuterRadiusFactorSpeed = 0.0;
                    }
                }
                else
                {
                    OuterRadiusFactorSpeed -= timeElapsed;
                    if (OuterRadiusFactorSpeed < 0.0)
                    {
                        OuterRadiusFactorSpeed = 0.0;
                    }
                }
            }
            OuterRadiusFactor += OuterRadiusFactorSpeed * timeElapsed;
            if (OuterRadiusFactor < OuterRadiusFactorMinimum)
            {
                OuterRadiusFactor      = OuterRadiusFactorMinimum;
                OuterRadiusFactorSpeed = 0.0;
            }
            else if (OuterRadiusFactor > OuterRadiusFactorMaximum)
            {
                OuterRadiusFactor      = OuterRadiusFactorMaximum;
                OuterRadiusFactorSpeed = 0.0;
            }
        }
Пример #55
0
        private static void LoadEverythingThreaded()
        {
            Program.AppendToLogFile("Loading route file: " + CurrentRouteFile);
            string RailwayFolder = GetRailwayFolder(CurrentRouteFile);
            string ObjectFolder  = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object");
            string SoundFolder   = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound");

            // reset
            Game.Reset(true);
            Game.MinimalisticSimulation = true;
            // screen
            World.CameraTrackFollower = new TrackManager.TrackFollower {
                Train = null, CarIndex = -1
            };
            World.CameraMode = World.CameraViewMode.Interior;
            //First, check the format of the route file
            //RW routes were written for BVE1 / 2, and have a different command syntax
            bool IsRW = CsvRwRouteParser.isRWFile(CurrentRouteFile);

            Program.AppendToLogFile("Route file format is: " + (IsRW ? "RW" : "CSV"));
            CsvRwRouteParser.ParseRoute(CurrentRouteFile, IsRW, CurrentRouteEncoding, CurrentTrainFolder, ObjectFolder, SoundFolder, false);
            Thread createIllustrations = new Thread(Game.RouteInformation.LoadInformation)
            {
                IsBackground = true
            };

            createIllustrations.Start();
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            Game.CalculateSeaLevelConstants();
            if (Game.BogusPretrainInstructions.Length != 0)
            {
                double t = Game.BogusPretrainInstructions[0].Time;
                double p = Game.BogusPretrainInstructions[0].TrackPosition;
                for (int i = 1; i < Game.BogusPretrainInstructions.Length; i++)
                {
                    if (Game.BogusPretrainInstructions[i].Time > t)
                    {
                        t = Game.BogusPretrainInstructions[i].Time;
                    }
                    else
                    {
                        t += 1.0;
                        Game.BogusPretrainInstructions[i].Time = t;
                    }
                    if (Game.BogusPretrainInstructions[i].TrackPosition > p)
                    {
                        p = Game.BogusPretrainInstructions[i].TrackPosition;
                    }
                    else
                    {
                        p += 1.0;
                        Game.BogusPretrainInstructions[i].TrackPosition = p;
                    }
                }
            }
            if (Game.Stations.Length == 1)
            {
                //Log the fact that only a single station is present, as this is probably not right
                Program.AppendToLogFile("The processed route file only contains a single station.");
            }
            Program.AppendToLogFile("Route file loaded successfully.");
            RouteProgress = 1.0;
            // initialize trains
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            TrainManager.Trains = new TrainManager.Train[Game.PrecedingTrainTimeDeltas.Length + 1 + (Game.BogusPretrainInstructions.Length != 0 ? 1 : 0)];
            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                TrainManager.Trains[k] = new TrainManager.Train {
                    TrainIndex = k
                };
                if (k == TrainManager.Trains.Length - 1 & Game.BogusPretrainInstructions.Length != 0)
                {
                    TrainManager.Trains[k].State = TrainManager.TrainState.Bogus;
                }
                else
                {
                    TrainManager.Trains[k].State = TrainManager.TrainState.Pending;
                }
            }
            TrainManager.PlayerTrain = TrainManager.Trains[Game.PrecedingTrainTimeDeltas.Length];
            // load trains
            double TrainProgressMaximum = 0.7 + 0.3 * (double)TrainManager.Trains.Length;

            for (int k = 0; k < TrainManager.Trains.Length; k++)
            {
                //Sleep for 10ms to allow route loading locks to release
                Thread.Sleep(20);
                if (TrainManager.Trains[k].State == TrainManager.TrainState.Bogus)
                {
                    // bogus train
                    string TrainData = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility", "PreTrain"), "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, System.Text.Encoding.UTF8, TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainManager.Trains[k].InitializeCarSounds();
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.3 / TrainProgressMaximum;
                    TrainProgressCurrentSum   += TrainProgressCurrentWeight;
                }
                else
                {
                    // real train
                    Program.AppendToLogFile("Loading player train: " + CurrentTrainFolder);
                    TrainProgressCurrentWeight = 0.1 / TrainProgressMaximum;
                    string TrainData = OpenBveApi.Path.CombineFile(CurrentTrainFolder, "train.dat");
                    TrainDatParser.ParseTrainData(TrainData, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    TrainProgressCurrentWeight = 0.2 / TrainProgressMaximum;
                    SoundCfgParser.ParseSoundConfig(CurrentTrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    // door open/close speed
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer != null & TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer);
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorOpenL.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorOpenR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency = 0.8;
                            }
                        }
                        if (TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency <= 0.0)
                        {
                            if (TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer != null & TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer);
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer.Duration;
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer);
                                double a = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                            }
                            else if (TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer != null)
                            {
                                Sounds.LoadBuffer(TrainManager.Trains[k].Cars[i].Sounds.DoorCloseL.Buffer);
                                double b = TrainManager.Trains[k].Cars[i].Sounds.DoorCloseR.Buffer.Duration;
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                            }
                            else
                            {
                                TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency = 0.8;
                            }
                        }
                        const double f = 0.015;
                        const double g = 2.75;
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenFrequency  /= TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch;
                        TrainManager.Trains[k].Cars[i].Specs.DoorCloseFrequency /= TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch;

                        /*
                         * Remove the following two lines, then the pitch at which doors play
                         * takes their randomized opening and closing times into account.
                         * */
                        TrainManager.Trains[k].Cars[i].Specs.DoorOpenPitch  = 1.0;
                        TrainManager.Trains[k].Cars[i].Specs.DoorClosePitch = 1.0;
                    }
                }
                for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                {
                    TrainManager.Trains[k].Cars[i].FrontAxle.Follower.Train = TrainManager.Trains[k];
                    TrainManager.Trains[k].Cars[i].RearAxle.Follower.Train  = TrainManager.Trains[k];
                    TrainManager.Trains[k].Cars[i].BeaconReceiver.Train     = TrainManager.Trains[k];
                }
                // add panel section
                if (k == TrainManager.PlayerTrain.TrainIndex)
                {
                    TrainManager.Trains[k].Cars[TrainManager.Trains[k].DriverCar].CarSections             = new TrainManager.CarSection[1];
                    TrainManager.Trains[k].Cars[TrainManager.Trains[k].DriverCar].CarSections[0].Elements = new ObjectManager.AnimatedObject[] { };
                    TrainManager.Trains[k].Cars[TrainManager.Trains[k].DriverCar].CarSections[0].Overlay  = true;
                    TrainProgressCurrentWeight = 0.7 / TrainProgressMaximum;
                    TrainManager.ParsePanelConfig(CurrentTrainFolder, CurrentTrainEncoding, TrainManager.Trains[k]);
                    TrainProgressCurrentSum += TrainProgressCurrentWeight;
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    Program.AppendToLogFile("Train panel loaded sucessfully.");
                }
                // add exterior section
                if (TrainManager.Trains[k].State != TrainManager.TrainState.Bogus)
                {
                    ObjectManager.UnifiedObject[] CarObjects;
                    ObjectManager.UnifiedObject[] BogieObjects;
                    ExtensionsCfgParser.ParseExtensionsConfig(CurrentTrainFolder, CurrentTrainEncoding, out CarObjects, out BogieObjects, TrainManager.Trains[k]);
                    System.Threading.Thread.Sleep(1); if (Cancel)
                    {
                        return;
                    }
                    //Stores the current array index of the bogie object to add
                    //Required as there are two bogies per car, and we're using a simple linear array....
                    int currentBogieObject = 0;
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        if (CarObjects[i] == null)
                        {
                            // load default exterior object
                            string file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                            ObjectManager.StaticObject so = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, ObjectManager.ObjectLoadMode.Normal, false, false, false);
                            if (so == null)
                            {
                                CarObjects[i] = null;
                            }
                            else
                            {
                                double sx = TrainManager.Trains[k].Cars[i].Width;
                                double sy = TrainManager.Trains[k].Cars[i].Height;
                                double sz = TrainManager.Trains[k].Cars[i].Length;
                                CsvB3dObjectParser.ApplyScale(so, sx, sy, sz);
                                CarObjects[i] = so;
                            }
                        }
                        if (CarObjects[i] != null)
                        {
                            // add object
                            int j = TrainManager.Trains[k].Cars[i].CarSections.Length;
                            Array.Resize <TrainManager.CarSection>(ref TrainManager.Trains[k].Cars[i].CarSections, j + 1);
                            if (CarObjects[i] is ObjectManager.StaticObject)
                            {
                                ObjectManager.StaticObject s = (ObjectManager.StaticObject)CarObjects[i];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements                       = new ObjectManager.AnimatedObject[1];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0]                    = new ObjectManager.AnimatedObject();
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].States             = new ObjectManager.AnimatedObjectState[1];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].States[0].Position = new Vector3(0.0, 0.0, 0.0);
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].States[0].Object   = s;
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].CurrentState       = 0;
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements[0].ObjectIndex        = ObjectManager.CreateDynamicObject();
                            }
                            else if (CarObjects[i] is ObjectManager.AnimatedObjectCollection)
                            {
                                ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)CarObjects[i];
                                TrainManager.Trains[k].Cars[i].CarSections[j].Elements = new ObjectManager.AnimatedObject[a.Objects.Length];
                                for (int h = 0; h < a.Objects.Length; h++)
                                {
                                    TrainManager.Trains[k].Cars[i].CarSections[j].Elements[h]             = a.Objects[h];
                                    TrainManager.Trains[k].Cars[i].CarSections[j].Elements[h].ObjectIndex = ObjectManager.CreateDynamicObject();
                                }
                            }
                        }

                        //Load bogie objects
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            int j = TrainManager.Trains[k].Cars[i].FrontBogie.CarSections.Length;
                            Array.Resize <TrainManager.CarSection>(ref TrainManager.Trains[k].Cars[i].FrontBogie.CarSections, j + 1);
                            if (BogieObjects[currentBogieObject] is ObjectManager.StaticObject)
                            {
                                ObjectManager.StaticObject s = (ObjectManager.StaticObject)BogieObjects[currentBogieObject];
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements                       = new ObjectManager.AnimatedObject[1];
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[0]                    = new ObjectManager.AnimatedObject();
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[0].States             = new ObjectManager.AnimatedObjectState[1];
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[0].States[0].Position = new Vector3(0.0, 0.0, 0.0);
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[0].States[0].Object   = s;
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[0].CurrentState       = 0;
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[0].ObjectIndex        = ObjectManager.CreateDynamicObject();
                            }
                            else if (BogieObjects[currentBogieObject] is ObjectManager.AnimatedObjectCollection)
                            {
                                ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)BogieObjects[currentBogieObject];
                                TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements = new ObjectManager.AnimatedObject[a.Objects.Length];
                                for (int h = 0; h < a.Objects.Length; h++)
                                {
                                    TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[h]             = a.Objects[h];
                                    TrainManager.Trains[k].Cars[i].FrontBogie.CarSections[j].Elements[h].ObjectIndex = ObjectManager.CreateDynamicObject();
                                }
                            }
                        }
                        currentBogieObject++;
                        //Can't think of a better way to do this than two functions......
                        if (BogieObjects[currentBogieObject] != null)
                        {
                            int j = TrainManager.Trains[k].Cars[i].RearBogie.CarSections.Length;
                            Array.Resize <TrainManager.CarSection>(ref TrainManager.Trains[k].Cars[i].RearBogie.CarSections, j + 1);
                            if (BogieObjects[currentBogieObject] is ObjectManager.StaticObject)
                            {
                                ObjectManager.StaticObject s = (ObjectManager.StaticObject)BogieObjects[currentBogieObject];
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements                       = new ObjectManager.AnimatedObject[1];
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[0]                    = new ObjectManager.AnimatedObject();
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[0].States             = new ObjectManager.AnimatedObjectState[1];
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[0].States[0].Position = new Vector3(0.0, 0.0, 0.0);
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[0].States[0].Object   = s;
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[0].CurrentState       = 0;
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[0].ObjectIndex        = ObjectManager.CreateDynamicObject();
                            }
                            else if (BogieObjects[currentBogieObject] is ObjectManager.AnimatedObjectCollection)
                            {
                                ObjectManager.AnimatedObjectCollection a = (ObjectManager.AnimatedObjectCollection)BogieObjects[currentBogieObject];
                                TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements = new ObjectManager.AnimatedObject[a.Objects.Length];
                                for (int h = 0; h < a.Objects.Length; h++)
                                {
                                    TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[h]             = a.Objects[h];
                                    TrainManager.Trains[k].Cars[i].RearBogie.CarSections[j].Elements[h].ObjectIndex = ObjectManager.CreateDynamicObject();
                                }
                            }
                        }
                        currentBogieObject++;
                    }
                }
                // place cars
                {
                    double z = 0.0;
                    for (int i = 0; i < TrainManager.Trains[k].Cars.Length; i++)
                    {
                        //Front axle track position
                        TrainManager.Trains[k].Cars[i].FrontAxle.Follower.TrackPosition = z - 0.5 * TrainManager.Trains[k].Cars[i].Length + TrainManager.Trains[k].Cars[i].FrontAxle.Position;
                        //Bogie for front axle
                        TrainManager.Trains[k].Cars[i].FrontBogie.FrontAxle.Follower.TrackPosition = TrainManager.Trains[k].Cars[i].FrontAxle.Follower.TrackPosition - 0.5 * TrainManager.Trains[k].Cars[i].FrontBogie.Length + TrainManager.Trains[k].Cars[i].FrontBogie.FrontAxle.Position;
                        TrainManager.Trains[k].Cars[i].FrontBogie.RearAxle.Follower.TrackPosition  = TrainManager.Trains[k].Cars[i].FrontAxle.Follower.TrackPosition - 0.5 * TrainManager.Trains[k].Cars[i].FrontBogie.Length + TrainManager.Trains[k].Cars[i].FrontBogie.RearAxle.Position;
                        //Rear axle track position
                        TrainManager.Trains[k].Cars[i].RearAxle.Follower.TrackPosition = z - 0.5 * TrainManager.Trains[k].Cars[i].Length + TrainManager.Trains[k].Cars[i].RearAxle.Position;
                        //Bogie for rear axle
                        TrainManager.Trains[k].Cars[i].RearBogie.FrontAxle.Follower.TrackPosition = TrainManager.Trains[k].Cars[i].RearAxle.Follower.TrackPosition - 0.5 * TrainManager.Trains[k].Cars[i].RearBogie.Length + TrainManager.Trains[k].Cars[i].RearBogie.FrontAxle.Position;
                        TrainManager.Trains[k].Cars[i].RearBogie.RearAxle.Follower.TrackPosition  = TrainManager.Trains[k].Cars[i].RearAxle.Follower.TrackPosition - 0.5 * TrainManager.Trains[k].Cars[i].RearBogie.Length + TrainManager.Trains[k].Cars[i].RearBogie.RearAxle.Position;
                        //Beacon reciever (AWS, ATC etc.)
                        TrainManager.Trains[k].Cars[i].BeaconReceiver.TrackPosition = z - 0.5 * TrainManager.Trains[k].Cars[i].Length + TrainManager.Trains[k].Cars[i].BeaconReceiverPosition;
                        z -= TrainManager.Trains[k].Cars[i].Length;
                        if (i < TrainManager.Trains[k].Cars.Length - 1)
                        {
                            z -= 0.5 * (TrainManager.Trains[k].Couplers[i].MinimumDistanceBetweenCars + TrainManager.Trains[k].Couplers[i].MaximumDistanceBetweenCars);
                        }
                    }
                }
                // configure ai / timetable
                if (TrainManager.Trains[k] == TrainManager.PlayerTrain)
                {
                    TrainManager.Trains[k].TimetableDelta = 0.0;
                }
                else if (TrainManager.Trains[k].State != TrainManager.TrainState.Bogus)
                {
                    TrainManager.Trains[k].AI                  = new Game.SimpleHumanDriverAI(TrainManager.Trains[k]);
                    TrainManager.Trains[k].TimetableDelta      = Game.PrecedingTrainTimeDeltas[k];
                    TrainManager.Trains[k].Specs.DoorOpenMode  = TrainManager.DoorMode.Manual;
                    TrainManager.Trains[k].Specs.DoorCloseMode = TrainManager.DoorMode.Manual;
                }
            }
            TrainProgress = 1.0;
            // finished created objects
            System.Threading.Thread.Sleep(1); if (Cancel)
            {
                return;
            }
            ObjectManager.FinishCreatingObjects();
            // update sections
            if (Game.Sections.Length > 0)
            {
                Game.UpdateSection(Game.Sections.Length - 1);
            }
            // load plugin
            for (int i = 0; i < TrainManager.Trains.Length; i++)
            {
                if (TrainManager.Trains[i].State != TrainManager.TrainState.Bogus)
                {
                    if (TrainManager.Trains[i] == TrainManager.PlayerTrain)
                    {
                        if (!PluginManager.LoadCustomPlugin(TrainManager.Trains[i], CurrentTrainFolder, CurrentTrainEncoding))
                        {
                            PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], CurrentTrainFolder);
                        }
                    }
                    else
                    {
                        PluginManager.LoadDefaultPlugin(TrainManager.Trains[i], CurrentTrainFolder);
                    }
                }
            }
        }
Пример #56
0
            /// <summary>Sets the driver handles or the virtual handles.</summary>
            /// <param name="handles">The handles.</param>
            /// <param name="virtualHandles">Whether to set the virtual handles.</param>
            private void SetHandles(Handles handles, bool virtualHandles)
            {
                /*
                 * Process the handles.
                 */
                if (this.Train.Specs.SingleHandle & handles.BrakeNotch != 0)
                {
                    handles.PowerNotch = 0;
                }

                /*
                 * Process the reverser.
                 */
                if (handles.Reverser >= -1 & handles.Reverser <= 1)
                {
                    if (virtualHandles)
                    {
                        this.Train.Specs.CurrentReverser.Actual = handles.Reverser;
                    }
                    else
                    {
                        TrainManager.ApplyReverser(this.Train, handles.Reverser, false);
                    }
                }
                else
                {
                    if (virtualHandles)
                    {
                        this.Train.Specs.CurrentReverser.Actual = this.Train.Specs.CurrentReverser.Driver;
                    }
                    this.PluginValid = false;
                }

                /*
                 * Process the power.
                 * */
                if (handles.PowerNotch >= 0 & handles.PowerNotch <= this.Train.Specs.MaximumPowerNotch)
                {
                    if (virtualHandles)
                    {
                        this.Train.Specs.CurrentPowerNotch.Safety = handles.PowerNotch;
                    }
                    else
                    {
                        TrainManager.ApplyNotch(this.Train, handles.PowerNotch, false, 0, true);
                    }
                }
                else
                {
                    if (virtualHandles)
                    {
                        this.Train.Specs.CurrentPowerNotch.Safety = this.Train.Specs.CurrentPowerNotch.Driver;
                    }
                    this.PluginValid = false;
                }
//				if (handles.BrakeNotch != 0) {
//					if (virtualHandles) {
//						this.Train.Specs.CurrentPowerNotch.Safety = 0;
//					}
//				}

                /*
                 * Process the brakes.
                 * */
                if (virtualHandles)
                {
                    this.Train.Specs.CurrentEmergencyBrake.Safety = false;
                    this.Train.Specs.CurrentHoldBrake.Actual      = false;
                }
                if (this.Train.Cars[this.Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake)
                {
                    if (handles.BrakeNotch == 0)
                    {
                        if (virtualHandles)
                        {
                            this.Train.Specs.AirBrake.Handle.Safety = TrainManager.AirBrakeHandleState.Release;
                        }
                        else
                        {
                            TrainManager.UnapplyEmergencyBrake(this.Train);
                            TrainManager.ApplyAirBrakeHandle(this.Train, TrainManager.AirBrakeHandleState.Release);
                        }
                    }
                    else if (handles.BrakeNotch == 1)
                    {
                        if (virtualHandles)
                        {
                            this.Train.Specs.AirBrake.Handle.Safety = TrainManager.AirBrakeHandleState.Lap;
                        }
                        else
                        {
                            TrainManager.UnapplyEmergencyBrake(this.Train);
                            TrainManager.ApplyAirBrakeHandle(this.Train, TrainManager.AirBrakeHandleState.Lap);
                        }
                    }
                    else if (handles.BrakeNotch == 2)
                    {
                        if (virtualHandles)
                        {
                            this.Train.Specs.AirBrake.Handle.Safety = TrainManager.AirBrakeHandleState.Service;
                        }
                        else
                        {
                            TrainManager.UnapplyEmergencyBrake(this.Train);
                            TrainManager.ApplyAirBrakeHandle(this.Train, TrainManager.AirBrakeHandleState.Release);
                        }
                    }
                    else if (handles.BrakeNotch == 3)
                    {
                        if (virtualHandles)
                        {
                            this.Train.Specs.AirBrake.Handle.Safety       = TrainManager.AirBrakeHandleState.Service;
                            this.Train.Specs.CurrentEmergencyBrake.Safety = true;
                        }
                        else
                        {
                            TrainManager.ApplyAirBrakeHandle(this.Train, TrainManager.AirBrakeHandleState.Service);
                            TrainManager.ApplyEmergencyBrake(this.Train);
                        }
                    }
                    else
                    {
                        this.PluginValid = false;
                    }
                }
                else
                {
                    if (this.Train.Specs.HasHoldBrake)
                    {
                        if (handles.BrakeNotch == this.Train.Specs.MaximumBrakeNotch + 2)
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentEmergencyBrake.Safety = true;
                                this.Train.Specs.CurrentBrakeNotch.Safety     = this.Train.Specs.MaximumBrakeNotch;
                            }
                            else
                            {
                                TrainManager.ApplyHoldBrake(this.Train, false);
                                TrainManager.ApplyNotch(this.Train, 0, true, this.Train.Specs.MaximumBrakeNotch, false);
                                TrainManager.ApplyEmergencyBrake(this.Train);
                            }
                        }
                        else if (handles.BrakeNotch >= 2 & handles.BrakeNotch <= this.Train.Specs.MaximumBrakeNotch + 1)
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentBrakeNotch.Safety = handles.BrakeNotch - 1;
                            }
                            else
                            {
                                TrainManager.UnapplyEmergencyBrake(this.Train);
                                TrainManager.ApplyHoldBrake(this.Train, false);
                                TrainManager.ApplyNotch(this.Train, 0, true, handles.BrakeNotch - 1, false);
                            }
                        }
                        else if (handles.BrakeNotch == 1)
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentBrakeNotch.Safety = 0;
                                this.Train.Specs.CurrentHoldBrake.Actual  = true;
                            }
                            else
                            {
                                TrainManager.UnapplyEmergencyBrake(this.Train);
                                TrainManager.ApplyNotch(this.Train, 0, true, 0, false);
                                TrainManager.ApplyHoldBrake(this.Train, true);
                            }
                        }
                        else if (handles.BrakeNotch == 0)
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentBrakeNotch.Safety = 0;
                            }
                            else
                            {
                                TrainManager.UnapplyEmergencyBrake(this.Train);
                                TrainManager.ApplyNotch(this.Train, 0, true, 0, false);
                                TrainManager.ApplyHoldBrake(this.Train, false);
                            }
                        }
                        else
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentBrakeNotch.Safety = this.Train.Specs.CurrentBrakeNotch.Driver;
                            }
                            this.PluginValid = false;
                        }
                    }
                    else
                    {
                        if (handles.BrakeNotch == this.Train.Specs.MaximumBrakeNotch + 1)
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentEmergencyBrake.Safety = true;
                                this.Train.Specs.CurrentBrakeNotch.Safety     = this.Train.Specs.MaximumBrakeNotch;
                            }
                            else
                            {
                                TrainManager.ApplyHoldBrake(this.Train, false);
                                TrainManager.ApplyEmergencyBrake(this.Train);
                            }
                        }
                        else if (handles.BrakeNotch >= 0 & handles.BrakeNotch <= this.Train.Specs.MaximumBrakeNotch | this.Train.Specs.CurrentBrakeNotch.DelayedChanges.Length == 0)
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentBrakeNotch.Safety = handles.BrakeNotch;
                            }
                            else
                            {
                                TrainManager.UnapplyEmergencyBrake(this.Train);
                                TrainManager.ApplyNotch(this.Train, 0, true, handles.BrakeNotch, false);
                            }
                        }
                        else
                        {
                            if (virtualHandles)
                            {
                                this.Train.Specs.CurrentBrakeNotch.Safety = this.Train.Specs.CurrentBrakeNotch.Driver;
                            }
                            this.PluginValid = false;
                        }
                    }
                }

                /*
                 * Process the const speed system.
                 * */
                this.Train.Specs.CurrentConstSpeed = handles.ConstSpeed & this.Train.Specs.HasConstSpeed;
            }
Пример #57
0
 /// <summary>Stops all sounds that are attached to the specified train.</summary>
 /// <param name="train">The train.</param>
 internal static void StopAllSounds(TrainManager.Train train)
 {
     for (int i = 0; i < SourceCount; i++) {
         if (Sources[i].Train == train) {
             if (Sources[i].State == SoundSourceState.Playing) {
                 Al.alDeleteSources(1, ref Sources[i].OpenAlSourceName);
                 Sources[i].OpenAlSourceName = 0;
             }
             Sources[i].State = SoundSourceState.Stopped;
         }
     }
 }
Пример #58
0
            private void PerformDefault()
            {
                if (Train.Derailed)
                {
                    if (Train.Handles.EmergencyBrake.Driver != true)
                    {
                        Train.ApplyEmergencyBrake();
                    }
                    return;
                }
                // personality
                double spd = Train.CurrentSpeed;

                if (Train.Station >= 0 & Train.StationState == TrainManager.TrainStopState.Boarding)
                {
                    if (Train.Station != this.LastStation)
                    {
                        this.LastStation = Train.Station;
                        double time;
                        if (Stations[Train.Station].ArrivalTime >= 0.0)
                        {
                            time = Stations[Train.Station].ArrivalTime - Train.TimetableDelta;
                        }
                        else if (Stations[Train.Station].DepartureTime >= 0.0)
                        {
                            time = Stations[Train.Station].DepartureTime - Train.TimetableDelta;
                            if (time > SecondsSinceMidnight)
                            {
                                time -= Stations[Train.Station].StopTime;
                                if (time > SecondsSinceMidnight)
                                {
                                    time = double.MinValue;
                                }
                            }
                        }
                        else
                        {
                            time = double.MinValue;
                        }
                        if (time != double.MinValue)
                        {
                            const double largeThreshold    = 30.0;
                            const double largeChangeFactor = 0.0025;
                            const double smallThreshold    = 15.0;
                            const double smallChange       = 0.05;
                            double       diff = SecondsSinceMidnight - time;
                            if (diff < -largeThreshold)
                            {
                                /* The AI is too fast. Decrease the preferred speed. */
                                this.CurrentSpeedFactor -= largeChangeFactor * (-diff - largeThreshold);
                                if (this.CurrentSpeedFactor < 0.7)
                                {
                                    this.CurrentSpeedFactor = 0.7;
                                }
                            }
                            else if (diff > largeThreshold)
                            {
                                /* The AI is too slow. Increase the preferred speed. */
                                this.CurrentSpeedFactor += largeChangeFactor * (diff - largeThreshold);
                                if (this.CurrentSpeedFactor > 1.1)
                                {
                                    this.CurrentSpeedFactor = 1.1;
                                }
                            }
                            else if (Math.Abs(diff) < smallThreshold)
                            {
                                /* The AI is at about the right speed. Change the preferred speed toward the personality default. */
                                if (this.CurrentSpeedFactor < this.PersonalitySpeedFactor)
                                {
                                    this.CurrentSpeedFactor += smallChange;
                                    if (this.CurrentSpeedFactor > this.PersonalitySpeedFactor)
                                    {
                                        this.CurrentSpeedFactor = this.PersonalitySpeedFactor;
                                    }
                                }
                                else if (this.CurrentSpeedFactor > this.PersonalitySpeedFactor)
                                {
                                    this.CurrentSpeedFactor -= smallChange;
                                    if (this.CurrentSpeedFactor < this.PersonalitySpeedFactor)
                                    {
                                        this.CurrentSpeedFactor = this.PersonalitySpeedFactor;
                                    }
                                }
                            }
                        }
                    }
                }
                // door states
                bool doorsopen = false;

                for (int i = 0; i < Train.Cars.Length; i++)
                {
                    for (int j = 0; j < Train.Cars[i].Doors.Length; j++)
                    {
                        if (Train.Cars[i].Doors[j].State != 0.0)
                        {
                            doorsopen = true;
                            break;
                        }
                        if (doorsopen)
                        {
                            break;
                        }
                    }
                }
                // do the ai
                Train.Specs.CurrentConstSpeed = false;
                Train.ApplyHoldBrake(false);
                int stopIndex = Train.Station >= 0 ? Game.Stations[Train.Station].GetStopIndex(Train.Cars.Length) : -1;

                if (Train.CurrentSectionLimit == 0.0)
                {
                    // passing red signal
                    Train.ApplyEmergencyBrake();
                    Train.ApplyNotch(-1, true, 1, true);
                    CurrentInterval = 0.5;
                }
                else if (doorsopen | Train.StationState == TrainManager.TrainStopState.Boarding)
                {
                    // door opened or boarding at station
                    this.PowerNotchAtWhichWheelSlipIsObserved = Train.Handles.Power.MaximumNotch + 1;
                    if (Train.Station >= 0 && Stations[Train.Station].Type != StationType.Normal && Stations[Train.Station].Type != StationType.RequestStop && Train == TrainManager.PlayerTrain)
                    {
                        // player's terminal station
                        if (Train.Plugin == null || Train.Plugin.LastReverser == -2)
                        {
                            Train.ApplyReverser(0, false);
                        }
                        Train.ApplyNotch(-1, true, 1, true);
                        Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                        Train.ApplyEmergencyBrake();
                        CurrentInterval = 1.0;
                    }
                    else
                    {
                        CurrentInterval = 1.0;
                        Train.ApplyNotch(-1, true, 0, true);
                        if (Train.Handles.Brake is TrainManager.AirBrakeHandle)
                        {
                            if (Train.Cars[Train.DriverCar].CarBrake.brakeCylinder.CurrentPressure < 0.3 * Train.Cars[Train.DriverCar].CarBrake.brakeCylinder.ServiceMaximumPressure)
                            {
                                Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                            }
                            else if (Train.Cars[Train.DriverCar].CarBrake.brakeCylinder.CurrentPressure > 0.9 * Train.Cars[Train.DriverCar].CarBrake.brakeCylinder.EmergencyMaximumPressure)
                            {
                                Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                            }
                            else
                            {
                                Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Lap);
                            }
                        }
                        else
                        {
                            int b;
                            if (Math.Abs(spd) < 0.02)
                            {
                                b = (int)Math.Ceiling(0.5 * (double)Train.Handles.Brake.MaximumNotch);
                                CurrentInterval = 0.3;
                            }
                            else
                            {
                                b = Train.Handles.Brake.MaximumNotch;
                            }
                            if (Train.Handles.Brake.Driver < b)
                            {
                                Train.ApplyNotch(0, true, 1, true);
                            }
                            else if (Train.Handles.Brake.Driver > b)
                            {
                                Train.ApplyNotch(0, true, -1, true);
                            }
                        }
                        Train.UnapplyEmergencyBrake();
                        if (Train.Station >= 0 & Train.StationState == TrainManager.TrainStopState.Completed)
                        {
                            // ready for departure - close doors
                            if (Train.Specs.DoorOpenMode != TrainManager.DoorMode.Automatic && Train.Specs.DoorInterlockState == DoorInterlockStates.Unlocked)
                            {
                                TrainManager.CloseTrainDoors(Train, true, true);
                            }
                        }
                        else if (Train.Station >= 0 & Train.StationState == TrainManager.TrainStopState.Boarding)
                        {
                        }
                        else
                        {
                            // not at station - close doors
                            if (Train.Specs.DoorOpenMode != TrainManager.DoorMode.Automatic && Train.Specs.DoorInterlockState == DoorInterlockStates.Unlocked)
                            {
                                TrainManager.CloseTrainDoors(Train, true, true);
                            }
                        }
                    }
                }
                else if (Train.Station >= 0 && stopIndex >= 0 && Train.StationDistanceToStopPoint < Stations[Train.Station].Stops[stopIndex].BackwardTolerance && (StopsAtStation(Train.Station, Train) & (Stations[Train.Station].OpenLeftDoors | Stations[Train.Station].OpenRightDoors) & Math.Abs(Train.CurrentSpeed) < 0.25 & Train.StationState == TrainManager.TrainStopState.Pending))
                {
                    // arrived at station - open doors
                    if (Train.Specs.DoorOpenMode != TrainManager.DoorMode.Automatic && Train.Specs.DoorInterlockState == DoorInterlockStates.Unlocked)
                    {
                        TrainManager.OpenTrainDoors(Train, Stations[Train.Station].OpenLeftDoors, Stations[Train.Station].OpenRightDoors);
                    }
                    CurrentInterval = 1.0;
                }
                else if (Train.Station >= 0 && stopIndex >= 0 && Stations[Train.Station].Type != StationType.Normal && Stations[Train.Station].Type != StationType.RequestStop && Train == TrainManager.PlayerTrain && Train.StationDistanceToStopPoint < Stations[Train.Station].Stops[stopIndex].BackwardTolerance && -Train.StationDistanceToStopPoint < Stations[Train.Station].Stops[stopIndex].ForwardTolerance && Math.Abs(Train.CurrentSpeed) < 0.25)
                {
                    // player's terminal station (not boarding any longer)
                    if (Train.Plugin != null || Train.Plugin.LastReverser == -2)
                    {
                        Train.ApplyReverser(0, false);
                    }
                    Train.ApplyNotch(-1, true, 1, true);
                    Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                    Train.ApplyEmergencyBrake();
                    CurrentInterval = 10.0;
                }
                else
                {
                    // drive
                    Train.ApplyReverser(1, false);
                    if (Train.Cars[Train.DriverCar].FrontAxle.CurrentWheelSlip | Train.Cars[Train.DriverCar].RearAxle.CurrentWheelSlip)
                    {
                        // react to wheel slip
                        if (Train.Handles.Power.Driver > 1)
                        {
                            this.PowerNotchAtWhichWheelSlipIsObserved = Train.Handles.Power.Driver;
                            Train.ApplyNotch(-1, true, -1, true);
                            Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                            this.CurrentInterval = 2.5;
                            return;
                        }
                    }
                    // initialize
                    double acc = Train.Specs.CurrentAverageAcceleration;
                    double lim = PrecedingTrainSpeedLimit * 1.2;
                    if (Train.CurrentRouteLimit < lim)
                    {
                        lim = Train.CurrentRouteLimit;
                    }
                    if (Train.CurrentSectionLimit < lim)
                    {
                        lim = Train.CurrentSectionLimit;
                    }
                    double powerstart, powerend, brakestart;
                    if (double.IsPositiveInfinity(lim))
                    {
                        powerstart = lim;
                        powerend   = lim;
                        brakestart = lim;
                    }
                    else
                    {
                        lim *= this.CurrentSpeedFactor;
                        if (spd < 8.0)
                        {
                            powerstart = 0.75 * lim;
                            powerend   = 0.95 * lim;
                        }
                        else
                        {
                            powerstart = lim - 2.5;
                            powerend   = lim - 1.5;
                        }
                        if (this.BrakeMode)
                        {
                            brakestart = powerend;
                        }
                        else
                        {
                            brakestart = lim + 0.5;
                        }
                    }
                    double dec = 0.0;
                    double decelerationCruise;                       /* power below this deceleration, cruise above */
                    double decelerationStart;                        /* brake above this deceleration, cruise below */
                    double decelerationStep;                         /* the deceleration step per brake notch */
                    double BrakeDeceleration = Train.Cars[Train.DriverCar].CarBrake.DecelerationAtServiceMaximumPressure(Train.Handles.Brake.Actual, Train.Cars[Train.DriverCar].Specs.CurrentSpeed);
                    for (int i = 0; i < Train.Cars.Length; i++)
                    {
                        if (Train.Cars[i].Specs.IsMotorCar)
                        {
                            if (Train.Cars[Train.DriverCar].Specs.MotorDeceleration != 0 && Train.Cars[Train.DriverCar].Specs.MotorDeceleration < BrakeDeceleration)
                            {
                                BrakeDeceleration = Train.Cars[Train.DriverCar].Specs.MotorDeceleration;
                            }
                            break;
                        }
                    }
                    if (Train.Handles.Brake is TrainManager.AirBrakeHandle | Train.Handles.Brake.MaximumNotch <= 0)
                    {
                        decelerationCruise = 0.3 * BrakeDeceleration;
                        decelerationStart  = 0.5 * BrakeDeceleration;
                        decelerationStep   = 0.1 * BrakeDeceleration;
                    }
                    else if (Train.Handles.Brake.MaximumNotch <= 2)
                    {
                        decelerationCruise = 0.2 * BrakeDeceleration;
                        decelerationStart  = 0.4 * BrakeDeceleration;
                        decelerationStep   = 0.5 * BrakeDeceleration;
                    }
                    else
                    {
                        decelerationCruise = 0.2 * BrakeDeceleration;
                        decelerationStart  = 0.5 * BrakeDeceleration;
                        decelerationStep   = BrakeDeceleration / (double)Train.Handles.Brake.MaximumNotch;
                    }
                    if (this.CurrentSpeedFactor >= 1.0)
                    {
                        decelerationCruise *= 1.25;
                        decelerationStart  *= 1.25;
                        decelerationStep   *= 1.25;
                    }

                    if (spd > 0.0 & spd > brakestart)
                    {
                        dec = decelerationStep + 0.1 * (spd - brakestart);
                    }
                    bool reduceDecelerationCruiseAndStart = false;
                    // look ahead
                    double lookahead    = (Train.Station >= 0 ? 150.0 : 50.0) + (spd * spd) / (2.0 * decelerationCruise);
                    double tp           = Train.FrontCarTrackPosition();
                    double stopDistance = double.MaxValue;
                    {
                        // next station stop
                        int te = Train.Cars[0].FrontAxle.Follower.LastTrackElement;
                        for (int i = te; i < TrackManager.Tracks[0].Elements.Length; i++)
                        {
                            double stp = TrackManager.Tracks[0].Elements[i].StartingTrackPosition;
                            if (tp + lookahead <= stp)
                            {
                                break;
                            }
                            for (int j = 0; j < TrackManager.Tracks[0].Elements[i].Events.Length; j++)
                            {
                                if (TrackManager.Tracks[0].Elements[i].Events[j] is TrackManager.StationStartEvent && Train.NextStopSkipped == TrainManager.StopSkipMode.None)
                                {
                                    TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.Tracks[0].Elements[i].Events[j];
                                    if (StopsAtStation(e.StationIndex, Train) & Train.LastStation != e.StationIndex)
                                    {
                                        int s = Game.Stations[e.StationIndex].GetStopIndex(Train.Cars.Length);
                                        if (s >= 0)
                                        {
                                            double dist = Stations[e.StationIndex].Stops[s].TrackPosition - tp;
                                            if (dist > 0.0 & dist < stopDistance)
                                            {
                                                stopDistance = dist;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    {
                        // events
                        int te = Train.Cars[0].FrontAxle.Follower.LastTrackElement;
                        for (int i = te; i < TrackManager.Tracks[0].Elements.Length; i++)
                        {
                            double stp = TrackManager.Tracks[0].Elements[i].StartingTrackPosition;
                            if (tp + lookahead <= stp)
                            {
                                break;
                            }
                            for (int j = 0; j < TrackManager.Tracks[0].Elements[i].Events.Length; j++)
                            {
                                if (TrackManager.Tracks[0].Elements[i].Events[j] is TrackManager.LimitChangeEvent)
                                {
                                    // speed limit
                                    TrackManager.LimitChangeEvent e = (TrackManager.LimitChangeEvent)TrackManager.Tracks[0].Elements[i].Events[j];
                                    if (e.NextSpeedLimit < spd)
                                    {
                                        double dist = stp + e.TrackPositionDelta - tp;
                                        double edec = (spd * spd - e.NextSpeedLimit * e.NextSpeedLimit * this.CurrentSpeedFactor) / (2.0 * dist);
                                        if (edec > dec)
                                        {
                                            dec = edec;
                                        }
                                    }
                                }
                                else if (TrackManager.Tracks[0].Elements[i].Events[j] is TrackManager.SectionChangeEvent)
                                {
                                    // section
                                    TrackManager.SectionChangeEvent e = (TrackManager.SectionChangeEvent)TrackManager.Tracks[0].Elements[i].Events[j];
                                    if (stp + e.TrackPositionDelta > tp)
                                    {
                                        if (!CurrentRoute.Sections[e.NextSectionIndex].Invisible & CurrentRoute.Sections[e.NextSectionIndex].CurrentAspect >= 0)
                                        {
                                            double elim = CurrentRoute.Sections[e.NextSectionIndex].Aspects[CurrentRoute.Sections[e.NextSectionIndex].CurrentAspect].Speed * this.CurrentSpeedFactor;
                                            if (elim < spd | spd <= 0.0)
                                            {
                                                double dist = stp + e.TrackPositionDelta - tp;
                                                double edec;
                                                if (elim == 0.0)
                                                {
                                                    double redstopdist;
                                                    if (Train.Station >= 0 & Train.StationState == TrainManager.TrainStopState.Completed & dist < 120.0)
                                                    {
                                                        dist        = 1.0;
                                                        redstopdist = 25.0;
                                                    }
                                                    else if (Train.Station >= 0 & Train.StationState == TrainManager.TrainStopState.Pending | stopDistance < dist)
                                                    {
                                                        redstopdist = 1.0;
                                                    }
                                                    else if (spd > 9.72222222222222)
                                                    {
                                                        redstopdist = 55.0;
                                                    }
                                                    else
                                                    {
                                                        redstopdist = 35.0;
                                                    }
                                                    if (dist > redstopdist)
                                                    {
                                                        edec = (spd * spd) / (2.0 * (dist - redstopdist));
                                                    }
                                                    else
                                                    {
                                                        edec = BrakeDeceleration;
                                                    }
                                                    if (dist < 100.0)
                                                    {
                                                        reduceDecelerationCruiseAndStart = true;
                                                    }
                                                }
                                                else
                                                {
                                                    if (dist >= 1.0)
                                                    {
                                                        edec = (spd * spd - elim * elim) / (2.0 * dist);
                                                    }
                                                    else
                                                    {
                                                        edec = 0.0;
                                                    }
                                                }
                                                if (edec > dec)
                                                {
                                                    dec = edec;
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (TrackManager.Tracks[0].Elements[i].Events[j] is TrackManager.StationStartEvent && Train.NextStopSkipped == TrainManager.StopSkipMode.None)
                                {
                                    // station start
                                    if (Train.Station == -1)
                                    {
                                        TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.Tracks[0].Elements[i].Events[j];
                                        if (StopsAtStation(e.StationIndex, Train) & Train.LastStation != e.StationIndex)
                                        {
                                            int s = Game.Stations[e.StationIndex].GetStopIndex(Train.Cars.Length);
                                            if (s >= 0)
                                            {
                                                double dist = Stations[e.StationIndex].Stops[s].TrackPosition - tp;
                                                if (dist > -Stations[e.StationIndex].Stops[s].ForwardTolerance)
                                                {
                                                    if (dist < 25.0)
                                                    {
                                                        reduceDecelerationCruiseAndStart = true;
                                                    }
                                                    else if (this.CurrentSpeedFactor < 1.0)
                                                    {
                                                        dist -= 5.0;
                                                    }
                                                    var edec = spd * spd / (2.0 * dist);
                                                    if (edec > dec)
                                                    {
                                                        dec = edec;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (TrackManager.Tracks[0].Elements[i].Events[j] is TrackManager.StationStartEvent && Train.NextStopSkipped == TrainManager.StopSkipMode.Decelerate)
                                {
                                    // Brakes the train when passing through a request stop, which is not to be passed at linespeed
                                    if (Train.Station == -1)
                                    {
                                        TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.Tracks[0].Elements[i].Events[j];
                                        if (StopsAtStation(e.StationIndex, Train) & Train.LastStation != e.StationIndex)
                                        {
                                            int s = Game.Stations[e.StationIndex].GetStopIndex(Train.Cars.Length);
                                            if (s >= 0)
                                            {
                                                double dist = Stations[e.StationIndex].Stops[s].TrackPosition - tp;
                                                if (dist > -Stations[e.StationIndex].Stops[s].ForwardTolerance)
                                                {
                                                    if (dist < 25.0)
                                                    {
                                                        reduceDecelerationCruiseAndStart = true;
                                                    }
                                                    else if (this.CurrentSpeedFactor < 1.0)
                                                    {
                                                        dist -= 5.0;
                                                    }
                                                    if (dist > 25)
                                                    {
                                                        var edec = spd * spd / (2.0 * dist);
                                                        if (edec > dec)
                                                        {
                                                            dec = edec;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (TrackManager.Tracks[0].Elements[i].Events[j] is TrackManager.StationEndEvent && Train.NextStopSkipped == TrainManager.StopSkipMode.None)
                                {
                                    // station end
                                    if (Train.Station == -1)
                                    {
                                        TrackManager.StationEndEvent e = (TrackManager.StationEndEvent)TrackManager.Tracks[0].Elements[i].Events[j];
                                        if (StopsAtStation(e.StationIndex, Train) & Train.LastStation != e.StationIndex)
                                        {
                                            int s = Game.Stations[e.StationIndex].GetStopIndex(Train.Cars.Length);
                                            if (s >= 0)
                                            {
                                                double dist = Stations[e.StationIndex].Stops[s].TrackPosition - tp;
                                                if (dist > -Stations[e.StationIndex].Stops[s].ForwardTolerance)
                                                {
                                                    if (dist < 25.0)
                                                    {
                                                        reduceDecelerationCruiseAndStart = true;
                                                    }
                                                    else if (this.CurrentSpeedFactor < 1.0)
                                                    {
                                                        dist -= 5.0;
                                                    }
                                                    var edec = spd * spd / (2.0 * dist);
                                                    if (edec > dec)
                                                    {
                                                        dec = edec;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                else if (TrackManager.Tracks[0].Elements[i].Events[j] is TrackManager.TrackEndEvent)
                                {
                                    // track end
                                    if (Train == TrainManager.PlayerTrain)
                                    {
                                        TrackManager.TrackEndEvent e = (TrackManager.TrackEndEvent)TrackManager.Tracks[0].Elements[i].Events[j];
                                        double dist = stp + e.TrackPositionDelta - tp;
                                        double edec;
                                        if (dist >= 15.0)
                                        {
                                            edec = spd * spd / (2.0 * dist);
                                        }
                                        else
                                        {
                                            edec = BrakeDeceleration;
                                        }
                                        if (edec > dec)
                                        {
                                            dec = edec;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // buffers ahead
                    if (Train == TrainManager.PlayerTrain)
                    {
                        for (int i = 0; i < BufferTrackPositions.Length; i++)
                        {
                            double dist = BufferTrackPositions[i] - tp;
                            if (dist > 0.0)
                            {
                                double edec;
                                if (dist >= 10.0)
                                {
                                    edec = spd * spd / (2.0 * dist);
                                }
                                else if (dist >= 5.0)
                                {
                                    Train.ApplyNotch(-1, true, 1, true);
                                    Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                                    this.CurrentInterval = 0.1;
                                    return;
                                }
                                else
                                {
                                    Train.ApplyNotch(-1, true, 1, true);
                                    Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                                    Train.ApplyEmergencyBrake();
                                    this.CurrentInterval = 10.0;
                                    return;
                                }
                                if (edec > dec)
                                {
                                    dec = edec;
                                }
                            }
                        }
                    }
                    // trains ahead
                    for (int i = 0; i < TrainManager.Trains.Length; i++)
                    {
                        if (TrainManager.Trains[i] != Train && TrainManager.Trains[i].State == TrainState.Available)
                        {
                            double pos =
                                TrainManager.Trains[i].Cars[TrainManager.Trains[i].Cars.Length - 1].RearAxle.Follower.TrackPosition -
                                TrainManager.Trains[i].Cars[TrainManager.Trains[i].Cars.Length - 1].RearAxle.Position -
                                0.5 * TrainManager.Trains[i].Cars[TrainManager.Trains[i].Cars.Length - 1].Length;
                            double dist = pos - tp;
                            if (dist > -10.0 & dist < lookahead)
                            {
                                const double minDistance = 10.0;
                                const double maxDistance = 100.0;
                                double       edec;
                                if (dist > minDistance)
                                {
                                    double shift = 0.75 * minDistance + 1.0 * spd;
                                    edec = spd * spd / (2.0 * (dist - shift));
                                }
                                else if (dist > 0.5 * minDistance)
                                {
                                    Train.ApplyNotch(-1, true, 1, true);
                                    Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                                    this.CurrentInterval = 0.1;
                                    return;
                                }
                                else
                                {
                                    Train.ApplyNotch(-1, true, 1, true);
                                    Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                                    Train.ApplyEmergencyBrake();
                                    this.CurrentInterval = 1.0;
                                    return;
                                }
                                if (dist < maxDistance)
                                {
                                    reduceDecelerationCruiseAndStart = true;
                                }
                                if (edec > dec)
                                {
                                    dec = edec;
                                }
                            }
                        }
                    }
                    Train.UnapplyEmergencyBrake();
                    // current station
                    if (Train.Station >= 0 & Train.StationState == TrainManager.TrainStopState.Pending)
                    {
                        if (StopsAtStation(Train.Station, Train))
                        {
                            int s = Game.Stations[Train.Station].GetStopIndex(Train.Cars.Length);
                            if (s >= 0)
                            {
                                double dist = Stations[Train.Station].Stops[s].TrackPosition - tp;
                                if (dist > 0.0)
                                {
                                    if (dist < 25.0)
                                    {
                                        reduceDecelerationCruiseAndStart = true;
                                    }
                                    else if (this.CurrentSpeedFactor < 1.0)
                                    {
                                        dist -= 5.0;
                                    }
                                    var edec = spd * spd / (2.0 * dist);
                                    if (edec > dec)
                                    {
                                        dec = edec;
                                    }
                                }
                                else
                                {
                                    dec = BrakeDeceleration;
                                }
                            }
                        }
                    }
                    // power / brake
                    if (reduceDecelerationCruiseAndStart)
                    {
                        decelerationCruise *= 0.3;
                        decelerationStart  *= 0.3;
                    }
                    double brakeModeBrakeThreshold = 0.75 * decelerationStart + 0.25 * decelerationCruise;
                    if (!BrakeMode & dec > decelerationStart | BrakeMode & dec > brakeModeBrakeThreshold | false)
                    {
                        // brake
                        BrakeMode = true;
                        double decdiff = -acc - dec;
                        if (decdiff < -decelerationStep)
                        {
                            // brake start
                            if (Train.Handles.Power.Driver == 0)
                            {
                                Train.ApplyNotch(0, true, 1, true);
                                Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service);
                            }
                            else
                            {
                                Train.ApplyNotch(-1, true, 0, true);
                            }
                            CurrentInterval *= 0.4;
                            if (CurrentInterval < 0.3)
                            {
                                CurrentInterval = 0.3;
                            }
                        }
                        else if (decdiff > decelerationStep)
                        {
                            // brake stop
                            Train.ApplyNotch(-1, true, -1, true);
                            Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                            CurrentInterval *= 0.4;
                            if (CurrentInterval < 0.3)
                            {
                                CurrentInterval = 0.3;
                            }
                        }
                        else
                        {
                            // keep brake
                            Train.ApplyNotch(-1, true, 0, true);
                            Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Lap);
                            CurrentInterval *= 1.2;
                            if (CurrentInterval > 1.0)
                            {
                                CurrentInterval = 1.0;
                            }
                        }
                        if (Train.Handles.Power.Driver == 0 & Train.Handles.Brake.Driver == 0)
                        {
                            Train.ApplyHoldBrake(Train.Handles.HasHoldBrake);
                        }
                        if (Train.Handles.Brake is TrainManager.AirBrakeHandle)
                        {
                            CurrentInterval = 0.1;
                        }
                    }
                    else if (dec > decelerationCruise)
                    {
                        // cut power/brake
                        BrakeMode = false;
                        Train.ApplyNotch(-1, true, -1, true);
                        Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                        if (Train.Handles.Power.Driver == 0 & Train.Handles.Brake.Driver == 0)
                        {
                            Train.ApplyHoldBrake(Train.Handles.HasHoldBrake);
                        }
                        CurrentInterval *= 0.4;
                        if (CurrentInterval < 0.3)
                        {
                            CurrentInterval = 0.3;
                        }
                    }
                    else
                    {
                        // power
                        BrakeMode = false;
                        double acclim;
                        if (!double.IsInfinity(lim))
                        {
                            double d = lim - spd;
                            if (d > 0.0)
                            {
                                acclim = 0.1 / (0.1 * d + 1.0) - 0.12;
                            }
                            else
                            {
                                acclim = -1.0;
                            }
                        }
                        else
                        {
                            acclim = -1.0;
                        }
                        if (spd < powerstart)
                        {
                            // power start (under-speed)
                            if (Train.Handles.Brake.Driver == 0)
                            {
                                if (Train.Handles.Power.Driver < this.PowerNotchAtWhichWheelSlipIsObserved - 1)
                                {
                                    Train.ApplyNotch(1, true, 0, true);
                                }
                            }
                            else
                            {
                                Train.ApplyNotch(0, true, -1, true);
                            }
                            Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                            if (double.IsPositiveInfinity(powerstart))
                            {
                                CurrentInterval = 0.3 + 0.1 * Train.Handles.Power.Driver;
                            }
                            else
                            {
                                double p = (double)Train.Handles.Power.Driver / (double)Train.Handles.Power.MaximumNotch;
                                CurrentInterval = 0.3 + 15.0 * p / (powerstart - spd + 1.0);
                            }
                            if (CurrentInterval > 1.3)
                            {
                                CurrentInterval = 1.3;
                            }
                        }
                        else if (spd > powerend)
                        {
                            // power end (over-speed)
                            Train.ApplyNotch(-1, true, -1, true);
                            Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                            CurrentInterval *= 0.3;
                            if (CurrentInterval < 0.2)
                            {
                                CurrentInterval = 0.2;
                            }
                        }
                        else if (acc < acclim)
                        {
                            // power start (under-acceleration)
                            if (Train.Handles.Brake.Driver == 0)
                            {
                                if (Train.Handles.Power.Driver < this.PowerNotchAtWhichWheelSlipIsObserved - 1)
                                {
                                    if (Train.Handles.Power.Driver == Train.Handles.Power.Actual)
                                    {
                                        Train.ApplyNotch(1, true, 0, true);
                                    }
                                }
                            }
                            else
                            {
                                Train.ApplyNotch(0, true, -1, true);
                            }
                            Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                            CurrentInterval = 1.3;
                        }
                        else
                        {
                            // keep power
                            Train.ApplyNotch(0, true, -1, true);
                            Train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Release);
                            if (Train.Handles.Power.Driver != 0)
                            {
                                Train.Specs.CurrentConstSpeed = Train.Specs.HasConstSpeed;
                            }
                            if (Train.Handles.Power.Driver == 0 & Train.Handles.Brake.Driver == 0)
                            {
                                Train.ApplyHoldBrake(Train.Handles.HasHoldBrake);
                            }
                            CurrentInterval *= 1.1;
                            if (CurrentInterval > 1.5)
                            {
                                CurrentInterval = 1.5;
                            }
                        }
                    }
                }
            }
Пример #59
0
		// execute function script
		private static void ExecuteFunctionScript(FunctionScript Function, TrainManager.Train Train, int CarIndex, World.Vector3D Position, double TrackPosition, int SectionIndex, bool IsPartOfTrain, double TimeElapsed) {
			int s = 0, c = 0;
			for (int i = 0; i < Function.Instructions.Length; i++) {
				switch (Function.Instructions[i]) {
						// system
					case Instructions.SystemHalt:
						i = Function.Instructions.Length;
						break;
					case Instructions.SystemConstant:
						Function.Stack[s] = Function.Constants[c];
						s++; c++; break;
					case Instructions.SystemConstantArray:
						{
							int n = (int)Function.Instructions[i + 1];
							for (int j = 0; j < n; j++) {
								Function.Stack[s + j] = Function.Constants[c + j];
							} s += n; c += n; i++;
						} break;
					case Instructions.SystemValue:
						Function.Stack[s] = Function.LastResult;
						s++; break;
					case Instructions.SystemDelta:
						Function.Stack[s] = TimeElapsed;
						s++; break;
						// stack
					case Instructions.StackCopy:
						Function.Stack[s] = Function.Stack[s - 1];
						s++; break;
					case Instructions.StackSwap:
						{
							double a = Function.Stack[s - 1];
							Function.Stack[s - 1] = Function.Stack[s - 2];
							Function.Stack[s - 2] = a;
						} break;
						// math
					case Instructions.MathPlus:
						Function.Stack[s - 2] += Function.Stack[s - 1];
						s--; break;
					case Instructions.MathSubtract:
						Function.Stack[s - 2] -= Function.Stack[s - 1];
						s--; break;
					case Instructions.MathMinus:
						Function.Stack[s - 1] = -Function.Stack[s - 1];
						break;
					case Instructions.MathTimes:
						Function.Stack[s - 2] *= Function.Stack[s - 1];
						s--; break;
					case Instructions.MathDivide:
						Function.Stack[s - 2] = Function.Stack[s - 1] == 0.0 ? 0.0 : Function.Stack[s - 2] / Function.Stack[s - 1];
						s--; break;
					case Instructions.MathReciprocal:
						Function.Stack[s - 1] = Function.Stack[s - 1] == 0.0 ? 0.0 : 1.0 / Function.Stack[s - 1];
						break;
					case Instructions.MathPower:
						{
							double a = Function.Stack[s - 2];
							double b = Function.Stack[s - 1];
							if (b == 2.0) {
								Function.Stack[s - 2] = a * a;
							} else if (b == 3.0) {
								Function.Stack[s - 2] = a * a * a;
							} else if (b == 4.0) {
								double t = a * a;
								Function.Stack[s - 2] = t * t;
							} else if (b == 5.0) {
								double t = a * a;
								Function.Stack[s - 2] = t * t * a;
							} else if (b == 6.0) {
								double t = a * a * a;
								Function.Stack[s - 2] = t * t;
							} else if (b == 7.0) {
								double t = a * a * a;
								Function.Stack[s - 2] = t * t * a;
							} else if (b == 8.0) {
								double t = a * a; t *= t;
								Function.Stack[s - 2] = t * t;
							} else if (b == 0.0) {
								Function.Stack[s - 2] = 1.0;
							} else if (b < 0.0) {
								Function.Stack[s - 2] = 0.0;
							} else {
								Function.Stack[s - 2] = Math.Pow(a, b);
							}
							s--; break;
						}
					case Instructions.MathIncrement:
						Function.Stack[s - 1] += 1.0;
						break;
					case Instructions.MathDecrement:
						Function.Stack[s - 1] -= 1.0;
						break;
					case Instructions.MathFusedMultiplyAdd:
						Function.Stack[s - 3] = Function.Stack[s - 3] * Function.Stack[s - 2] + Function.Stack[s - 1];
						s -= 2; break;
					case Instructions.MathQuotient:
						Function.Stack[s - 2] = Function.Stack[s - 1] == 0.0 ? 0.0 : Math.Floor(Function.Stack[s - 2] / Function.Stack[s - 1]);
						s--; break;
					case Instructions.MathMod:
						Function.Stack[s - 2] = Function.Stack[s - 1] == 0.0 ? 0.0 : Function.Stack[s - 2] - Function.Stack[s - 1] * Math.Floor(Function.Stack[s - 2] / Function.Stack[s - 1]);
						s--; break;
					case Instructions.MathFloor:
						Function.Stack[s - 1] = Math.Floor(Function.Stack[s - 1]);
						break;
					case Instructions.MathCeiling:
						Function.Stack[s - 1] = Math.Ceiling(Function.Stack[s - 1]);
						break;
					case Instructions.MathRound:
						Function.Stack[s - 1] = Math.Round(Function.Stack[s - 1]);
						break;
					case Instructions.MathMin:
						Function.Stack[s - 2] = Function.Stack[s - 2] < Function.Stack[s - 1] ? Function.Stack[s - 2] : Function.Stack[s - 1];
						s--; break;
					case Instructions.MathMax:
						Function.Stack[s - 2] = Function.Stack[s - 2] > Function.Stack[s - 1] ? Function.Stack[s - 2] : Function.Stack[s - 1];
						s--; break;
					case Instructions.MathAbs:
						Function.Stack[s - 1] = Math.Abs(Function.Stack[s - 1]);
						break;
					case Instructions.MathSign:
						Function.Stack[s - 1] = Math.Sign(Function.Stack[s - 1]);
						break;
					case Instructions.MathExp:
						Function.Stack[s - 1] = Math.Exp(Function.Stack[s - 1]);
						break;
					case Instructions.MathLog:
						Function.Stack[s - 1] = Log(Function.Stack[s - 1]);
						break;
					case Instructions.MathSqrt:
						Function.Stack[s - 1] = Sqrt(Function.Stack[s - 1]);
						break;
					case Instructions.MathSin:
						Function.Stack[s - 1] = Math.Sin(Function.Stack[s - 1]);
						break;
					case Instructions.MathCos:
						Function.Stack[s - 1] = Math.Cos(Function.Stack[s - 1]);
						break;
					case Instructions.MathTan:
						Function.Stack[s - 1] = Tan(Function.Stack[s - 1]);
						break;
					case Instructions.MathArcTan:
						Function.Stack[s - 1] = Math.Atan(Function.Stack[s - 1]);
						break;
						// comparisons
					case Instructions.CompareEqual:
						Function.Stack[s - 2] = Function.Stack[s - 2] == Function.Stack[s - 1] ? 1.0 : 0.0;
						s--; break;
					case Instructions.CompareUnequal:
						Function.Stack[s - 2] = Function.Stack[s - 2] != Function.Stack[s - 1] ? 1.0 : 0.0;
						s--; break;
					case Instructions.CompareLess:
						Function.Stack[s - 2] = Function.Stack[s - 2] < Function.Stack[s - 1] ? 1.0 : 0.0;
						s--; break;
					case Instructions.CompareGreater:
						Function.Stack[s - 2] = Function.Stack[s - 2] > Function.Stack[s - 1] ? 1.0 : 0.0;
						s--; break;
					case Instructions.CompareLessEqual:
						Function.Stack[s - 2] = Function.Stack[s - 2] <= Function.Stack[s - 1] ? 1.0 : 0.0;
						s--; break;
					case Instructions.CompareGreaterEqual:
						Function.Stack[s - 2] = Function.Stack[s - 2] >= Function.Stack[s - 1] ? 1.0 : 0.0;
						s--; break;
					case Instructions.CompareConditional:
						Function.Stack[s - 3] = Function.Stack[s - 3] != 0.0 ? Function.Stack[s - 2] : Function.Stack[s - 1];
						s -= 2; break;
						// logical
					case Instructions.LogicalNot:
						Function.Stack[s - 1] = Function.Stack[s - 1] != 0.0 ? 0.0 : 1.0;
						break;
					case Instructions.LogicalAnd:
						Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 & Function.Stack[s - 1] != 0.0 ? 1.0 : 0.0;
						s--; break;
					case Instructions.LogicalOr:
						Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 | Function.Stack[s - 1] != 0.0 ? 1.0 : 0.0;
						s--; break;
					case Instructions.LogicalNand:
						Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 & Function.Stack[s - 1] != 0.0 ? 0.0 : 1.0;
						s--; break;
					case Instructions.LogicalNor:
						Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 | Function.Stack[s - 1] != 0.0 ? 0.0 : 1.0;
						s--; break;
					case Instructions.LogicalXor:
						Function.Stack[s - 2] = Function.Stack[s - 2] != 0.0 ^ Function.Stack[s - 1] != 0.0 ? 1.0 : 0.0;
						s--; break;
						// time/camera
					case Instructions.TimeSecondsSinceMidnight:
						Function.Stack[s] = Game.SecondsSinceMidnight;
						s++; break;
					case Instructions.CameraDistance:
						{
							double dx = World.AbsoluteCameraPosition.X - Position.X;
							double dy = World.AbsoluteCameraPosition.Y - Position.Y;
							double dz = World.AbsoluteCameraPosition.Z - Position.Z;
							Function.Stack[s] = Math.Sqrt(dx * dx + dy * dy + dz * dz);
							s++;
						} break;
						// train
					case Instructions.TrainCars:
						if (Train != null) {
							Function.Stack[s] = (double)Train.Cars.Length;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.TrainSpeed:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.CurrentSpeed;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.TrainSpeedOfCar:
						if (Train != null) {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentSpeed;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.TrainSpeedometer:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.CurrentPerceivedSpeed;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.TrainSpeedometerOfCar:
						if (Train != null) {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentPerceivedSpeed;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.TrainAcceleration:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.CurrentAcceleration;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.TrainAccelerationOfCar:
						if (Train != null) {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentAcceleration;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.TrainAccelerationMotor:
						if (Train != null) {
							Function.Stack[s] = 0.0;
							for (int j = 0; j < Train.Cars.Length; j++) {
								if (Train.Cars[j].Specs.IsMotorCar) {
									// hack: CurrentAccelerationOutput does not distinguish between forward/backward
									if (Train.Cars[j].Specs.CurrentAccelerationOutput < 0.0) {
										Function.Stack[s] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Math.Sign(Train.Cars[j].Specs.CurrentSpeed);
									} else if (Train.Cars[j].Specs.CurrentAccelerationOutput > 0.0) {
										Function.Stack[s] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Train.Specs.CurrentReverser.Actual;
									} else {
										Function.Stack[s] = 0.0;
									}
									break;
								}
							}
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.TrainAccelerationMotorOfCar:
						if (Train != null) {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								// hack: CurrentAccelerationOutput does not distinguish between forward/backward
								if (Train.Cars[j].Specs.CurrentAccelerationOutput < 0.0) {
									Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Math.Sign(Train.Cars[j].Specs.CurrentSpeed);
								} else if (Train.Cars[j].Specs.CurrentAccelerationOutput > 0.0) {
									Function.Stack[s - 1] = Train.Cars[j].Specs.CurrentAccelerationOutput * (double)Train.Specs.CurrentReverser.Actual;
								} else {
									Function.Stack[s - 1] = 0.0;
								}
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.TrainDistance:
						if (Train != null) {
							double dist = double.MaxValue;
							for (int j = 0; j < Train.Cars.Length; j++) {
								double fx = Train.Cars[j].FrontAxle.Follower.WorldPosition.X - Position.X;
								double fy = Train.Cars[j].FrontAxle.Follower.WorldPosition.Y - Position.Y;
								double fz = Train.Cars[j].FrontAxle.Follower.WorldPosition.Z - Position.Z;
								double f = fx * fx + fy * fy + fz * fz;
								if (f < dist) dist = f;
								double rx = Train.Cars[j].RearAxle.Follower.WorldPosition.X - Position.X;
								double ry = Train.Cars[j].RearAxle.Follower.WorldPosition.Y - Position.Y;
								double rz = Train.Cars[j].RearAxle.Follower.WorldPosition.Z - Position.Z;
								double r = rx * rx + ry * ry + rz * rz;
								if (r < dist) dist = r;
							}
							Function.Stack[s] = Math.Sqrt(dist);
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.TrainDistanceToCar:
						if (Train != null) {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								double x = 0.5 * (Train.Cars[j].FrontAxle.Follower.WorldPosition.X + Train.Cars[j].RearAxle.Follower.WorldPosition.X) - Position.X;
								double y = 0.5 * (Train.Cars[j].FrontAxle.Follower.WorldPosition.Y + Train.Cars[j].RearAxle.Follower.WorldPosition.Y) - Position.Y;
								double z = 0.5 * (Train.Cars[j].FrontAxle.Follower.WorldPosition.Z + Train.Cars[j].RearAxle.Follower.WorldPosition.Z) - Position.Z;
								Function.Stack[s - 1] = Math.Sqrt(x * x + y * y + z * z);
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.TrainTrackDistance:
						if (Train != null) {
							int r = Train.Cars.Length - 1;
							double t0 = Train.Cars[0].FrontAxle.Follower.TrackPosition - Train.Cars[0].FrontAxlePosition + 0.5 * Train.Cars[0].Length;
							double t1 = Train.Cars[r].RearAxle.Follower.TrackPosition - Train.Cars[r].RearAxlePosition - 0.5 * Train.Cars[r].Length;
							Function.Stack[s] = TrackPosition > t0 ? TrackPosition - t0 : TrackPosition < t1 ? TrackPosition - t1 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.TrainTrackDistanceToCar:
						if (Train != null) {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								double p = 0.5 * (Train.Cars[j].FrontAxle.Follower.TrackPosition + Train.Cars[j].RearAxle.Follower.TrackPosition);
								Function.Stack[s - 1] = TrackPosition - p;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
						// door
					case Instructions.Doors:
						if (Train != null) {
							double a = 0.0;
							for (int j = 0; j < Train.Cars.Length; j++) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.Doors[k].State > a) {
										a = Train.Cars[j].Specs.Doors[k].State;
									}
								}
							}
							Function.Stack[s] = a;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.DoorsIndex:
						if (Train != null) {
							double a = 0.0;
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.Doors[k].State > a) {
										a = Train.Cars[j].Specs.Doors[k].State;
									}
								}
							}
							Function.Stack[s - 1] = a;
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.LeftDoors:
						if (Train != null) {
							double a = 0.0;
							for (int j = 0; j < Train.Cars.Length; j++) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.Doors[k].Direction == -1 & Train.Cars[j].Specs.Doors[k].State > a) {
										a = Train.Cars[j].Specs.Doors[k].State;
									}
								}
							}
							Function.Stack[s] = a;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.LeftDoorsIndex:
						if (Train != null) {
							double a = 0.0;
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.Doors[k].Direction == -1 & Train.Cars[j].Specs.Doors[k].State > a) {
										a = Train.Cars[j].Specs.Doors[k].State;
									}
								}
							}
							Function.Stack[s - 1] = a;
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.RightDoors:
						if (Train != null) {
							double a = 0.0;
							for (int j = 0; j < Train.Cars.Length; j++) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.Doors[k].Direction == 1 & Train.Cars[j].Specs.Doors[k].State > a) {
										a = Train.Cars[j].Specs.Doors[k].State;
									}
								}
							}
							Function.Stack[s] = a;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.RightDoorsIndex:
						if (Train != null) {
							double a = 0.0;
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.Doors[k].Direction == 1 & Train.Cars[j].Specs.Doors[k].State > a) {
										a = Train.Cars[j].Specs.Doors[k].State;
									}
								}
							}
							Function.Stack[s - 1] = a;
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.LeftDoorsTarget:
						if (Train != null) {
							bool q = false;
							for (int j = 0; j < Train.Cars.Length; j++) {
								if (Train.Cars[j].Specs.AnticipatedLeftDoorsOpened) {
									q = true;
									break;
								}
							}
							Function.Stack[s] = q ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.LeftDoorsTargetIndex:
						if (Train != null) {
							bool q = false;
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.AnticipatedLeftDoorsOpened) {
										q = true;
										break;
									}
								}
							}
							Function.Stack[s] = q ? 1.0 : 0.0;
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
					case Instructions.RightDoorsTarget:
						if (Train != null) {
							bool q = false;
							for (int j = 0; j < Train.Cars.Length; j++) {
								if (Train.Cars[j].Specs.AnticipatedRightDoorsOpened) {
									q = true;
									break;
								}
							}
							Function.Stack[s] = q ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.RightDoorsTargetIndex:
						if (Train != null) {
							bool q = false;
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) {
									if (Train.Cars[j].Specs.AnticipatedRightDoorsOpened) {
										q = true;
										break;
									}
								}
							}
							Function.Stack[s] = q ? 1.0 : 0.0;
						} else {
							Function.Stack[s - 1] = 0.0;
						}
						break;
						// handles
					case Instructions.ReverserNotch:
						if (Train != null) {
							Function.Stack[s] = (double)Train.Specs.CurrentReverser.Driver;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.PowerNotch:
						if (Train != null) {
							Function.Stack[s] = (double)Train.Specs.CurrentPowerNotch.Driver;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.PowerNotches:
						if (Train != null) {
							Function.Stack[s] = (double)Train.Specs.MaximumPowerNotch;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeNotch:
						if (Train != null) {
							if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) {
								Function.Stack[s] = (double)Train.Specs.AirBrake.Handle.Driver;
							} else {
								Function.Stack[s] = (double)Train.Specs.CurrentBrakeNotch.Driver;
							}
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeNotches:
						if (Train != null) {
							if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) {
								Function.Stack[s] = 2.0;
							} else {
								Function.Stack[s] = (double)Train.Specs.MaximumBrakeNotch;
							}
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeNotchLinear:
						if (Train != null) {
							if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) {
								if (Train.Specs.CurrentEmergencyBrake.Driver) {
									Function.Stack[s] = 3.0;
								} else {
									Function.Stack[s] = (double)Train.Specs.AirBrake.Handle.Driver;
								}
							} else if (Train.Specs.HasHoldBrake) {
								if (Train.Specs.CurrentEmergencyBrake.Driver) {
									Function.Stack[s] = (double)Train.Specs.MaximumBrakeNotch + 2.0;
								} else if (Train.Specs.CurrentBrakeNotch.Driver > 0) {
									Function.Stack[s] = (double)Train.Specs.CurrentBrakeNotch.Driver + 1.0;
								} else {
									Function.Stack[s] = Train.Specs.CurrentHoldBrake.Driver ? 1.0 : 0.0;
								}
							} else {
								if (Train.Specs.CurrentEmergencyBrake.Driver) {
									Function.Stack[s] = (double)Train.Specs.MaximumBrakeNotch + 1.0;
								} else {
									Function.Stack[s] = (double)Train.Specs.CurrentBrakeNotch.Driver;
								}
							}
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeNotchesLinear:
						if (Train != null) {
							if (Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) {
								Function.Stack[s] = 3.0;
							} else if (Train.Specs.HasHoldBrake) {
								Function.Stack[s] = Train.Specs.MaximumBrakeNotch + 2.0;
							} else {
								Function.Stack[s] = Train.Specs.MaximumBrakeNotch + 1.0;
							}
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.EmergencyBrake:
						if (Train != null) {
							Function.Stack[s] = Train.Specs.CurrentEmergencyBrake.Driver ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.HasAirBrake:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[Train.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.HoldBrake:
						if (Train != null) {
							Function.Stack[s] = Train.Specs.CurrentHoldBrake.Driver ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.HasHoldBrake:
						if (Train != null) {
							Function.Stack[s] = Train.Specs.HasHoldBrake ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.ConstSpeed:
						if (Train != null) {
							Function.Stack[s] = Train.Specs.CurrentConstSpeed ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.HasConstSpeed:
						if (Train != null) {
							Function.Stack[s] = Train.Specs.HasConstSpeed ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
						// brake
					case Instructions.BrakeMainReservoir:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.MainReservoirCurrentPressure;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeMainReservoirOfCar:
						if (Train == null) {
							Function.Stack[s - 1] = 0.0;
						} else {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.MainReservoirCurrentPressure;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						}
						break;
					case Instructions.BrakeEqualizingReservoir:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.EqualizingReservoirCurrentPressure;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeEqualizingReservoirOfCar:
						if (Train == null) {
							Function.Stack[s - 1] = 0.0;
						} else {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.EqualizingReservoirCurrentPressure;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						}
						break;
					case Instructions.BrakeBrakePipe:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.BrakePipeCurrentPressure;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeBrakePipeOfCar:
						if (Train == null) {
							Function.Stack[s - 1] = 0.0;
						} else {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.BrakePipeCurrentPressure;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						}
						break;
					case Instructions.BrakeBrakeCylinder:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.BrakeCylinderCurrentPressure;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeBrakeCylinderOfCar:
						if (Train == null) {
							Function.Stack[s - 1] = 0.0;
						} else {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.BrakeCylinderCurrentPressure;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						}
						break;
					case Instructions.BrakeStraightAirPipe:
						if (Train != null) {
							Function.Stack[s] = Train.Cars[CarIndex].Specs.AirBrake.StraightAirPipeCurrentPressure;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.BrakeStraightAirPipeOfCar:
						if (Train == null) {
							Function.Stack[s - 1] = 0.0;
						} else {
							int j = (int)Math.Round(Function.Stack[s - 1]);
							if (j < 0) j += Train.Cars.Length;
							if (j >= 0 & j < Train.Cars.Length) {
								Function.Stack[s - 1] = Train.Cars[j].Specs.AirBrake.StraightAirPipeCurrentPressure;
							} else {
								Function.Stack[s - 1] = 0.0;
							}
						}
						break;
						// safety
					case Instructions.SafetyPluginAvailable:
						if (Train == TrainManager.PlayerTrain) {
							Function.Stack[s] = TrainManager.PlayerTrain.Specs.Safety.Mode == TrainManager.SafetySystem.Plugin ? 1.0 : 0.0;
						} else {
							Function.Stack[s] = 0.0;
						}
						s++; break;
					case Instructions.SafetyPluginState:
						if (Train == null) {
							Function.Stack[s - 1] = 0.0;
						} else {
							int n = (int)Math.Round(Function.Stack[s - 1]);
							if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Plugin) {
								if (n >= 0 & n < PluginManager.CurrentPlugin.Panel.Length) {
									Function.Stack[s - 1] = (double)PluginManager.CurrentPlugin.Panel[n];
								} else {
									Function.Stack[s - 1] = 0.0;
								}
							} else {
								Function.Stack[s - 1] = 0.0;
								switch(n) {
									case 256:
										// ATS
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn) {
											if (Train.Specs.Safety.State == TrainManager.SafetyState.Normal | Train.Specs.Safety.State == TrainManager.SafetyState.Initialization) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 257:
										// ATS RUN (separate flashing)
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn) {
											if (Train.Specs.Safety.State == TrainManager.SafetyState.Ringing) {
												Function.Stack[s - 1] = 1.0;
											} else if (Train.Specs.Safety.State == TrainManager.SafetyState.Emergency | Train.Specs.Safety.State == TrainManager.SafetyState.Pattern | Train.Specs.Safety.State == TrainManager.SafetyState.Service) {
												Function.Stack[s - 1] = 2.0;
											}
										} break;
									case 258:
										// ATS RUN (integrated flashing)
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn) {
											if (Train.Specs.Safety.State == TrainManager.SafetyState.Ringing) {
												Function.Stack[s - 1] = 1.0;
											} else if (Train.Specs.Safety.State == TrainManager.SafetyState.Emergency | Train.Specs.Safety.State == TrainManager.SafetyState.Pattern | Train.Specs.Safety.State == TrainManager.SafetyState.Service) {
												if (((int)Math.Floor(2.0 * Game.SecondsSinceMidnight) & 1) == 0) {
													Function.Stack[s - 1] = 1.0;
												} else {
													Function.Stack[s - 1] = 0.0;
												}
											}
										} break;
									case 259:
										// P POWER
										if ((Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsSn | Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) & Train.Specs.Safety.Ats.AtsPAvailable) {
											Function.Stack[s - 1] = 1.0;
										} break;
									case 260:
										// PATTERN APPROACH
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) {
											if (Train.Specs.Safety.State == TrainManager.SafetyState.Pattern | Train.Specs.Safety.State == TrainManager.SafetyState.Service) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 261:
										// BRAKE RELEASE
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) {
											if (Train.Specs.Safety.Ats.AtsPOverride) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 262:
										// BRAKE OPERATION
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) {
											if (Train.Specs.Safety.State == TrainManager.SafetyState.Service & !Train.Specs.Safety.Ats.AtsPOverride) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 263:
										// ATS-P
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) {
											Function.Stack[s - 1] = 1.0;
										} break;
									case 264:
										// FAILURE
										if (Train.Specs.Safety.Mode != TrainManager.SafetySystem.None) {
											if (Train.Specs.Safety.State == TrainManager.SafetyState.Initialization) {
												Function.Stack[s - 1] = 1.0;
											} else if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.AtsP) {
												if (Train.Specs.Safety.State == TrainManager.SafetyState.Ringing | Train.Specs.Safety.State == TrainManager.SafetyState.Emergency) {
													Function.Stack[s - 1] = 1.0;
												}
											}
										} break;
									case 265:
										// ATC
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) {
											Function.Stack[s - 1] = 1.0;
										} break;
									case 266:
										// ATC POWER
										if ((Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc | Train.Specs.Safety.Mode != TrainManager.SafetySystem.None & Train.Specs.Safety.Atc.AutomaticSwitch)) {
											Function.Stack[s - 1] = 1.0;
										} break;
									case 267:
										// ATC SERVICE
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) {
											if (Train.Specs.Safety.State == TrainManager.SafetyState.Service) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 268:
										// ATC EMERGENCY
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) {
											if (!Train.Specs.Safety.Atc.Transmitting) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 269:
										// EB
										if (Train.Specs.Safety.Mode != TrainManager.SafetySystem.None) {
											if (Train.Specs.Safety.Eb.BellState == TrainManager.SafetyState.Ringing) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 270:
										// CONST SPEED
										if (Train.Specs.HasConstSpeed) {
											if (Train.Specs.CurrentConstSpeed) {
												Function.Stack[s - 1] = 1.0;
											}
										} break;
									case 271:
										// atc speedometer state
										if (Train.Specs.Safety.Mode == TrainManager.SafetySystem.Atc) {
											if (!Train.Specs.Safety.Atc.Transmitting) {
												Function.Stack[s - 1] = 0.0;
											} else {
												if (Train.Specs.Safety.Atc.SpeedRestriction < 4.1666) {
													Function.Stack[s - 1] = 1.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 6.9443) {
													Function.Stack[s - 1] = 2.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 12.4999) {
													Function.Stack[s - 1] = 3.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 15.2777) {
													Function.Stack[s - 1] = 4.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 18.0555) {
													Function.Stack[s - 1] = 5.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 20.8333) {
													Function.Stack[s - 1] = 6.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 24.9999) {
													Function.Stack[s - 1] = 7.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 27.7777) {
													Function.Stack[s - 1] = 8.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 30.5555) {
													Function.Stack[s - 1] = 9.0;
												} else if (Train.Specs.Safety.Atc.SpeedRestriction < 33.3333) {
													Function.Stack[s - 1] = 10.0;
												} else {
													Function.Stack[s - 1] = 11.0;
												}
											}
										} else {
											Function.Stack[s - 1] = 12.0;
										} break;

								}
							}
						} break;
						// timetable
					case Instructions.TimetableVisible:
						Function.Stack[s] = Timetable.CurrentTimetable == Timetable.TimetableState.Custom & Timetable.CustomTimetableAvailable ? 0.0 : -1.0;
						s++; break;
						// sections
					case Instructions.SectionAspectNumber:
						if (IsPartOfTrain) {
							int nextSectionIndex = Train.CurrentSectionIndex + 1;
							if (nextSectionIndex >= 0 & nextSectionIndex < Game.Sections.Length) {
								int a = Game.Sections[nextSectionIndex].CurrentAspect;
								if (a >= 0 & a < Game.Sections[nextSectionIndex].Aspects.Length) {
									Function.Stack[s] = (double)Game.Sections[nextSectionIndex].Aspects[a].Number;
								} else {
									Function.Stack[s] = 0;
								}
							}
						} else if (SectionIndex >= 0 & SectionIndex < Game.Sections.Length) {
							int a = Game.Sections[SectionIndex].CurrentAspect;
							if (a >= 0 & a < Game.Sections[SectionIndex].Aspects.Length) {
								Function.Stack[s] = (double)Game.Sections[SectionIndex].Aspects[a].Number;
							} else {
								Function.Stack[s] = 0;
							}
						} else {
							Function.Stack[s] = 0;
						}
						s++; break;
						// default
					default:
						throw new System.InvalidOperationException("The unknown instruction " + Function.Instructions[i].ToString() + " was encountered in ExecuteFunctionScript.");
				}
			}
			Function.LastResult = Function.Stack[s - 1];
		}
Пример #60
0
        private static void Main(string[] args)
        {
            // Add handler for UI thread exceptions
            Application.ThreadException += (CrashHandler.UIThreadException);

            // Force all WinForms errors to go through handler
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

            // This handler is for catching non-UI thread exceptions
            AppDomain.CurrentDomain.UnhandledException += (CrashHandler.CurrentDomain_UnhandledException);


            //Determine the current CPU architecture-
            //ARM will generally only support OpenGL-ES
            PortableExecutableKinds peKind;

            typeof(object).Module.GetPEKind(out peKind, out CurrentCPUArchitecture);

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            CurrentHost = new Host();
            if (IntPtr.Size == 4)
            {
                Joysticks = new JoystickManager32();
            }
            else
            {
                Joysticks = new JoystickManager64();
            }
            try {
                FileSystem = FileSystem.FromCommandLineArgs(args, CurrentHost);
                FileSystem.CreateFileSystem();
            } catch (Exception ex) {
                MessageBox.Show(Translations.GetInterfaceString("errors_filesystem_invalid") + Environment.NewLine + Environment.NewLine + ex.Message, Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand);
                return;
            }

            Renderer     = new NewRenderer();
            Sounds       = new Sounds();
            CurrentRoute = new CurrentRoute(CurrentHost, Renderer);

            //Platform specific startup checks
            // --- Check if we're running as root, and prompt not to ---
            if (CurrentHost.Platform == HostPlatform.GNULinux && getuid() == 0)
            {
                MessageBox.Show(
                    "You are currently running as the root user." + System.Environment.NewLine +
                    "This is a bad idea, please dont!", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand);
            }


            // --- load options and controls ---
            try
            {
                Interface.LoadOptions();
            }
            catch
            {
                // ignored
            }
            TrainManager = new TrainManager(CurrentHost, Renderer, Interface.CurrentOptions, FileSystem);

            //Switch between SDL2 and native backends; use native backend by default
            var options = new ToolkitOptions();

            if (Interface.CurrentOptions.PreferNativeBackend)
            {
                options.Backend = PlatformBackend.PreferNative;
            }
            Toolkit.Init(options);
            // --- load language ---
            string folder = Program.FileSystem.GetDataFolder("Languages");

            Translations.LoadLanguageFiles(folder);

            folder = Program.FileSystem.GetDataFolder("Cursors");
            Cursors.LoadCursorImages(folder);

            Interface.LoadControls(null, out Interface.CurrentControls);
            folder = Program.FileSystem.GetDataFolder("Controls");
            string file = OpenBveApi.Path.CombineFile(folder, "Default keyboard assignment.controls");

            Control[] controls;
            Interface.LoadControls(file, out controls);
            Interface.AddControls(ref Interface.CurrentControls, controls);

            InputDevicePlugin.LoadPlugins(Program.FileSystem);

            // --- check the command-line arguments for route and train ---
            formMain.MainDialogResult result = new formMain.MainDialogResult();
            CommandLine.ParseArguments(args, ref result);
            // --- check whether route and train exist ---
            if (result.RouteFile != null)
            {
                if (!System.IO.File.Exists(result.RouteFile))
                {
                    result.RouteFile = null;
                }
            }
            if (result.TrainFolder != null)
            {
                if (!System.IO.Directory.Exists(result.TrainFolder))
                {
                    result.TrainFolder = null;
                }
            }
            // --- if a route was provided but no train, try to use the route default ---
            if (result.RouteFile != null & result.TrainFolder == null)
            {
                string error;
                if (!CurrentHost.LoadPlugins(FileSystem, Interface.CurrentOptions, out error, TrainManager, Renderer))
                {
                    MessageBox.Show(error, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    throw new Exception("Unable to load the required plugins- Please reinstall OpenBVE");
                }
                Game.Reset(false);
                bool loaded = false;
                for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++)
                {
                    if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.CanLoadRoute(result.RouteFile))
                    {
                        object Route = (object)Program.CurrentRoute;                         //must cast to allow us to use the ref keyword.
                        Program.CurrentHost.Plugins[i].Route.LoadRoute(result.RouteFile, result.RouteEncoding, null, null, null, true, ref Route);
                        Program.CurrentRoute = (CurrentRoute)Route;
                        Program.Renderer.Lighting.OptionAmbientColor  = CurrentRoute.Atmosphere.AmbientLightColor;
                        Program.Renderer.Lighting.OptionDiffuseColor  = CurrentRoute.Atmosphere.DiffuseLightColor;
                        Program.Renderer.Lighting.OptionLightPosition = CurrentRoute.Atmosphere.LightPosition;
                        loaded = true;
                        break;
                    }
                }

                if (!CurrentHost.UnloadPlugins(out error))
                {
                    MessageBox.Show(error, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                if (!loaded)
                {
                    throw new Exception("No plugins capable of loading routefile " + result.RouteFile + " were found.");
                }
                if (!string.IsNullOrEmpty(Interface.CurrentOptions.TrainName))
                {
                    folder = System.IO.Path.GetDirectoryName(result.RouteFile);
                    while (true)
                    {
                        string trainFolder = OpenBveApi.Path.CombineDirectory(folder, "Train");
                        if (System.IO.Directory.Exists(trainFolder))
                        {
                            try
                            {
                                folder = OpenBveApi.Path.CombineDirectory(trainFolder, Interface.CurrentOptions.TrainName);
                            }
                            catch (Exception ex)
                            {
                                if (ex is ArgumentException)
                                {
                                    break;
                                }
                            }
                            if (System.IO.Directory.Exists(folder))
                            {
                                file = OpenBveApi.Path.CombineFile(folder, "train.dat");
                                if (System.IO.File.Exists(file))
                                {
                                    result.TrainFolder   = folder;
                                    result.TrainEncoding = System.Text.Encoding.UTF8;
                                    for (int j = 0; j < Interface.CurrentOptions.TrainEncodings.Length; j++)
                                    {
                                        if (string.Compare(Interface.CurrentOptions.TrainEncodings[j].Value, result.TrainFolder, StringComparison.InvariantCultureIgnoreCase) == 0)
                                        {
                                            result.TrainEncoding = System.Text.Encoding.GetEncoding(Interface.CurrentOptions.TrainEncodings[j].Codepage);
                                            break;
                                        }
                                    }
                                }
                            }
                            break;
                        }
                        if (folder == null)
                        {
                            continue;
                        }
                        System.IO.DirectoryInfo info = System.IO.Directory.GetParent(folder);
                        if (info != null)
                        {
                            folder = info.FullName;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
                Game.Reset(false);
            }
            // --- show the main menu if necessary ---
            if (result.RouteFile == null | result.TrainFolder == null)
            {
                Joysticks.RefreshJoysticks();

                // end HACK //
                result = formMain.ShowMainDialog(result);
            }
            else
            {
                result.Start = true;
                //Apply translations
                Translations.SetInGameLanguage(Translations.CurrentLanguageCode);
            }
            // --- start the actual program ---
            if (result.Start)
            {
                if (Initialize())
                {
                                        #if !DEBUG
                    try {
                                                #endif
                    MainLoop.StartLoopEx(result);
                                                #if !DEBUG
                }
                catch (Exception ex) {
                    bool found = false;
                    for (int i = 0; i < TrainManager.Trains.Length; i++)
                    {
                        if (TrainManager.Trains[i] != null && TrainManager.Trains[i].Plugin != null)
                        {
                            if (TrainManager.Trains[i].Plugin.LastException != null)
                            {
                                CrashHandler.LoadingCrash(ex.Message, true);
                                MessageBox.Show("The train plugin " + TrainManager.Trains[i].Plugin.PluginTitle + " caused a runtime exception: " + TrainManager.Trains[i].Plugin.LastException.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                                found            = true;
                                RestartArguments = "";
                                break;
                            }
                        }
                    }
                    if (!found)
                    {
                        if (ex is System.DllNotFoundException)
                        {
                            Interface.AddMessage(MessageType.Critical, false, "The required system library " + ex.Message + " was not found on the system.");
                            switch (ex.Message)
                            {
                            case "libopenal.so.1":
                                MessageBox.Show("openAL was not found on this system. \n Please install libopenal1 via your distribtion's package management system.", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand);
                                break;

                            default:
                                MessageBox.Show("The required system library " + ex.Message + " was not found on this system.", Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand);
                                break;
                            }
                        }
                        else
                        {
                            Interface.AddMessage(MessageType.Critical, false, "The route and train loader encountered the following critical error: " + ex.Message);
                            CrashHandler.LoadingCrash(ex + Environment.StackTrace, false);
                        }
                        RestartArguments = "";
                    }
                }
#endif
                }
                Deinitialize();
            }
            // --- restart the program if necessary ---
            if (RestartArguments != null)
            {
                string arguments;
                if (FileSystem.RestartArguments.Length != 0 & RestartArguments.Length != 0)
                {
                    arguments = FileSystem.RestartArguments + " " + RestartArguments;
                }
                else
                {
                    arguments = FileSystem.RestartArguments + RestartArguments;
                }
                try {
                    System.Diagnostics.Process.Start(System.IO.File.Exists(FileSystem.RestartProcess) ? FileSystem.RestartProcess : Application.ExecutablePath, arguments);
                } catch (Exception ex) {
                    MessageBox.Show(ex.Message + "\n\nProcess = " + FileSystem.RestartProcess + "\nArguments = " + arguments, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }