/// <summary>Attempts to load and parse the current train's panel configuration file.</summary> /// <param name="TrainPath">The absolute on-disk path to the train folder.</param> /// <param name="Encoding">The selected train encoding</param> internal void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding) { Cars[DriverCar].CarSections = new CarSection[1]; Cars[DriverCar].CarSections[0] = new CarSection(Program.CurrentHost, ObjectType.Overlay); string File = OpenBveApi.Path.CombineFile(TrainPath, "panel.xml"); if (!System.IO.File.Exists(File)) { //Try animated variant too File = OpenBveApi.Path.CombineFile(TrainPath, "panel.animated.xml"); } if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); try { /* * First load the XML. We use this to determine * whether this is a 2D or a 3D animated panel */ XDocument CurrentXML = XDocument.Load(File, LoadOptions.SetLineInfo); // Check for null if (CurrentXML.Root != null) { IEnumerable <XElement> DocumentElements = CurrentXML.Root.Elements("PanelAnimated"); if (DocumentElements.Any()) { PanelAnimatedXmlParser.ParsePanelAnimatedXml(System.IO.Path.GetFileName(File), TrainPath, this, DriverCar); if (Cars[DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D) { Cars[DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable; } } DocumentElements = CurrentXML.Root.Elements("Panel"); if (DocumentElements.Any()) { PanelXmlParser.ParsePanelXml(System.IO.Path.GetFileName(File), TrainPath, this, DriverCar); Cars[DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Program.Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.xml"); MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Program.RestartArguments = " "; Loading.Cancel = true; return; } if (Cars[DriverCar].CarSections[0].Groups[0].Elements.Any()) { OpenBVEGame.RunInRenderThread(() => { //Needs to be on the thread containing the openGL context Program.Renderer.InitializeVisibility(); }); Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance); return; } Interface.AddMessage(MessageType.Error, false, "The panel.xml file " + File + " failed to load. Falling back to legacy panel."); } else { File = OpenBveApi.Path.CombineFile(TrainPath, "panel.animated"); if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); if (System.IO.File.Exists(OpenBveApi.Path.CombineFile(TrainPath, "panel2.cfg")) || System.IO.File.Exists(OpenBveApi.Path.CombineFile(TrainPath, "panel.cfg"))) { Program.FileSystem.AppendToLogFile("INFO: This train contains both a 2D and a 3D panel. The 3D panel will always take precedence"); } UnifiedObject currentObject; Program.CurrentHost.LoadObject(File, Encoding, out currentObject); var a = currentObject as AnimatedObjectCollection; if (a != null) { //HACK: If a == null , loading our animated object completely failed (Missing objects?). Fallback to trying the panel2.cfg try { for (int i = 0; i < a.Objects.Length; i++) { Program.CurrentHost.CreateDynamicObject(ref a.Objects[i].internalObject); } Cars[DriverCar].CarSections[0].Groups[0].Elements = a.Objects; if (Cars[DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D) { Cars[DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable; Program.Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable; } Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance); return; } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.animated"); MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Program.RestartArguments = " "; Loading.Cancel = true; return; } } Interface.AddMessage(MessageType.Error, false, "The panel.animated file " + File + " failed to load. Falling back to 2D panel."); } } var Panel2 = false; try { File = OpenBveApi.Path.CombineFile(TrainPath, "panel2.cfg"); if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); Panel2 = true; Panel2CfgParser.ParsePanel2Config("panel2.cfg", TrainPath, Cars[DriverCar]); Cars[DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Program.Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; } else { File = OpenBveApi.Path.CombineFile(TrainPath, "panel.cfg"); if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); PanelCfgParser.ParsePanelConfig(TrainPath, Encoding, Cars[DriverCar]); Cars[DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Program.Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; } else { Program.Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", Panel2 ? "panel2.cfg" : "panel.cfg"); MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Program.RestartArguments = " "; Loading.Cancel = true; } }
private static void LoadEverythingThreaded() { string RailwayFolder = GetRailwayFolder(CurrentRouteFile); string ObjectFolder = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Object"); string SoundFolder = OpenBveApi.Path.CombineDirectory(RailwayFolder, "Sound"); Game.Reset(true); Game.MinimalisticSimulation = true; // screen Program.Renderer.Camera.CurrentMode = CameraViewMode.Interior; bool loaded = false; Program.FileSystem.AppendToLogFile("INFO: " + Program.CurrentHost.AvailableRoutePluginCount + " Route loading plugins available."); Program.FileSystem.AppendToLogFile("INFO: " + Program.CurrentHost.AvailableObjectPluginCount + " Object loading plugins available."); Program.FileSystem.AppendToLogFile("INFO: " + Program.CurrentHost.AvailableRoutePluginCount + " Sound loading plugins available."); for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.CanLoadRoute(CurrentRouteFile)) { object Route = (object)Program.CurrentRoute; //must cast to allow us to use the ref keyword. if (Program.CurrentHost.Plugins[i].Route.LoadRoute(CurrentRouteFile, CurrentRouteEncoding, CurrentTrainFolder, ObjectFolder, SoundFolder, false, ref Route)) { Program.CurrentRoute = (CurrentRoute)Route; Program.CurrentRoute.UpdateLighting(); loaded = true; break; } var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", System.IO.Path.GetFileName(CurrentRouteFile)); MessageBox.Show(currentError, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Hand); Interface.AddMessage(MessageType.Critical, false, "The route and train loader encountered the following critical error: " + Program.CurrentHost.Plugins[i].Route.LastException.Message); CrashHandler.LoadingCrash(Program.CurrentHost.Plugins[i].Route.LastException.Message, false); Program.RestartArguments = " "; Cancel = true; return; } } TrainManager.Derailments = Interface.CurrentOptions.Derailments; TrainManager.Toppling = Interface.CurrentOptions.Toppling; TrainManager.CurrentRoute = Program.CurrentRoute; if (!loaded) { throw new Exception("No plugins capable of loading routefile " + CurrentRouteFile + " were found."); } Thread createIllustrations = new Thread(Program.CurrentRoute.Information.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; } } } Program.Renderer.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."); // initialize trains System.Threading.Thread.Sleep(1); if (Cancel) { return; } Program.TrainManager.Trains = new TrainBase[Program.CurrentRoute.PrecedingTrainTimeDeltas.Length + 1 + (Program.CurrentRoute.BogusPreTrainInstructions.Length != 0 ? 1 : 0)]; for (int k = 0; k < Program.TrainManager.Trains.Length; k++) { if (k == Program.TrainManager.Trains.Length - 1 & Program.CurrentRoute.BogusPreTrainInstructions.Length != 0) { Program.TrainManager.Trains[k] = new TrainBase(TrainState.Bogus); } else { Program.TrainManager.Trains[k] = new TrainBase(TrainState.Pending); } } TrainManager.PlayerTrain = Program.TrainManager.Trains[Program.CurrentRoute.PrecedingTrainTimeDeltas.Length]; // load trains for (int k = 0; k < Program.TrainManager.Trains.Length; k++) { AbstractTrain currentTrain = Program.TrainManager.Trains[k]; for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { if (Program.CurrentHost.Plugins[i].Train != null && Program.CurrentHost.Plugins[i].Train.CanLoadTrain(CurrentTrainFolder)) { Program.CurrentHost.Plugins[i].Train.LoadTrain(CurrentTrainEncoding, CurrentTrainFolder, ref currentTrain, ref Interface.CurrentControls); break; } } Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance); // configure other properties if (currentTrain.IsPlayerTrain) { currentTrain.TimetableDelta = 0.0; if (Game.InitialReversedConsist) { currentTrain.Reverse(); TrainManager.PlayerTrain.CameraCar = currentTrain.DriverCar; Program.Renderer.Camera.CurrentRestriction = TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].CameraRestrictionMode; } } else if (currentTrain.State != TrainState.Bogus) { TrainBase train = currentTrain as TrainBase; currentTrain.AI = new Game.SimpleHumanDriverAI(train, Interface.CurrentOptions.PrecedingTrainSpeedLimit); currentTrain.TimetableDelta = Program.CurrentRoute.PrecedingTrainTimeDeltas[k]; train.Specs.DoorOpenMode = DoorMode.Manual; train.Specs.DoorCloseMode = DoorMode.Manual; } } // 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 CurrentTrain = 0; for (int i = 0; i < Program.TrainManager.Trains.Length; i++) { if (Program.TrainManager.Trains[i].State != TrainState.Bogus) { if (Program.TrainManager.Trains[i].IsPlayerTrain) { if (!Program.TrainManager.Trains[i].LoadCustomPlugin(Program.TrainManager.Trains[i].TrainFolder, CurrentTrainEncoding)) { Program.TrainManager.Trains[i].LoadDefaultPlugin(Program.TrainManager.Trains[i].TrainFolder); } } else { Program.TrainManager.Trains[i].LoadDefaultPlugin(Program.TrainManager.Trains[i].TrainFolder); } for (int j = 0; j < InputDevicePlugin.AvailablePluginInfos.Count; j++) { if (InputDevicePlugin.AvailablePluginInfos[j].Status == InputDevicePlugin.PluginInfo.PluginStatus.Enable && InputDevicePlugin.AvailablePlugins[j] is ITrainInputDevice) { ITrainInputDevice trainInputDevice = (ITrainInputDevice)InputDevicePlugin.AvailablePlugins[j]; trainInputDevice.SetVehicleSpecs(Program.TrainManager.Trains[i].vehicleSpecs()); } } } CurrentTrain++; } }
private void LoadCalibration(string calibrationFile) { if (!File.Exists(calibrationFile)) { return; } try { for (int i = 0; i < Calibration.Length; i++) { Calibration[i] = new AxisCalibration(); } XmlDocument currentXML = new XmlDocument(); currentXML.Load(calibrationFile); XmlNodeList documentNodes = currentXML.SelectNodes("openBVE/RailDriverCalibration"); if (documentNodes != null && documentNodes.Count != 0) { for (int i = 0; i < documentNodes.Count; i++) { int idx = -1; int lMin = 0; int lMax = 255; foreach (XmlNode node in documentNodes[i].ChildNodes) { switch (node.Name.ToLowerInvariant()) { case "axis": foreach (XmlNode n in node.ChildNodes) { switch (n.Name.ToLowerInvariant()) { case "index": if (!NumberFormats.TryParseIntVb6(n.InnerText, out idx)) { Program.FileSystem.AppendToLogFile(@"Invalid index in RailDriver calibration file"); } break; case "minimum": if (!NumberFormats.TryParseIntVb6(n.InnerText, out lMin)) { Program.FileSystem.AppendToLogFile(@"Invalid minimum in RailDriver calibration file"); } break; case "maximum": if (!NumberFormats.TryParseIntVb6(n.InnerText, out lMax)) { Program.FileSystem.AppendToLogFile(@"Invalid minimum in RailDriver calibration file"); } break; } } lMin = Math.Abs(lMin); lMax = Math.Abs(lMax); if (lMin > 255) { lMin = 255; } else if (lMin < 0) { lMin = 0; } if (lMax >= 255) { lMax = 255; } else if (lMax < 0) { lMax = 0; } if (lMin >= lMax) { throw new InvalidDataException(@"Maximum must be non-zero and greater than minimum."); } if (idx == -1) { throw new InvalidDataException(@"Invalid axis specified."); } Calibration[idx].Minimum = lMin; Calibration[idx].Maximum = lMax; break; } } } } } catch { for (int i = 0; i < Calibration.Length; i++) { Calibration[i] = new AxisCalibration(); } MessageBox.Show(Translations.GetInterfaceString("raildriver_config_error"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); //Clear the calibration file File.Delete(calibrationFile); } }
/// <summary>Exports the current score data to a file</summary> /// <param name="File">The file to write</param> internal static void ExportScore(string File) { CultureInfo Culture = CultureInfo.InvariantCulture; System.Text.StringBuilder Builder = new System.Text.StringBuilder(); string[][] Lines = new string[Game.ScoreLogCount + 1][]; Lines[0] = new string[] { Translations.GetInterfaceString("log_time"), Translations.GetInterfaceString("log_position"), Translations.GetInterfaceString("log_value"), Translations.GetInterfaceString("log_cumulative"), Translations.GetInterfaceString("log_reason") }; int Columns = Lines[0].Length; int TotalScore = 0; for (int i = 0; i < Game.ScoreLogCount; i++) { int j = i + 1; Lines[j] = new string[Columns]; { double x = Game.ScoreLogs[i].Time; int h = (int)Math.Floor(x / 3600.0); x -= (double)h * 3600.0; int m = (int)Math.Floor(x / 60.0); x -= (double)m * 60.0; int s = (int)Math.Floor(x); Lines[j][0] = h.ToString("00", Culture) + ":" + m.ToString("00", Culture) + ":" + s.ToString("00", Culture); } Lines[j][1] = Game.ScoreLogs[i].Position.ToString("0", Culture); Lines[j][2] = Game.ScoreLogs[i].Value.ToString(Culture); TotalScore += Game.ScoreLogs[i].Value; Lines[j][3] = TotalScore.ToString(Culture); Lines[j][4] = GetScoreText(Game.ScoreLogs[i].TextToken); } int[] Widths = new int[Columns]; for (int i = 0; i < Lines.Length; i++) { for (int j = 0; j < Columns; j++) { if (Lines[i][j].Length > Widths[j]) { Widths[j] = Lines[i][j].Length; } } } { // header rows int TotalWidth = 0; for (int j = 0; j < Columns; j++) { TotalWidth += Widths[j] + 2; } TotalWidth += Columns - 1; Builder.Append('╔'); Builder.Append('═', TotalWidth); Builder.Append("╗\n"); { Builder.Append('║'); Builder.Append((" " + Translations.GetInterfaceString("log_route") + " " + Game.LogRouteName).PadRight(TotalWidth, ' ')); Builder.Append("║\n║"); Builder.Append((" " + Translations.GetInterfaceString("log_train") + " " + Game.LogTrainName).PadRight(TotalWidth, ' ')); Builder.Append("║\n║"); Builder.Append((" " + Translations.GetInterfaceString("log_date") + " " + Game.LogDateTime.ToString("yyyy-MM-dd HH:mm:ss", Culture)).PadRight(TotalWidth, ' ')); Builder.Append("║\n"); } Builder.Append('╠'); Builder.Append('═', TotalWidth); Builder.Append("╣\n"); { double ratio = Game.CurrentScore.Maximum == 0 ? 0.0 : (double)Game.CurrentScore.CurrentValue / (double)Game.CurrentScore.Maximum; if (ratio < 0.0) { ratio = 0.0; } if (ratio > 1.0) { ratio = 1.0; } int index = (int)Math.Floor(ratio * (double)Translations.RatingsCount); if (index >= Translations.RatingsCount) { index = Translations.RatingsCount - 1; } string s; switch (Interface.CurrentOptions.GameMode) { case Interface.GameMode.Arcade: s = Translations.GetInterfaceString("mode_arcade"); break; case Interface.GameMode.Normal: s = Translations.GetInterfaceString("mode_normal"); break; case Interface.GameMode.Expert: s = Translations.GetInterfaceString("mode_expert"); break; default: s = Translations.GetInterfaceString("mode_unknown"); break; } Builder.Append('║'); Builder.Append((" " + Translations.GetInterfaceString("log_mode") + " " + s).PadRight(TotalWidth, ' ')); Builder.Append("║\n║"); Builder.Append((" " + Translations.GetInterfaceString("log_score") + " " + Game.CurrentScore.CurrentValue.ToString(Culture) + " / " + Game.CurrentScore.Maximum.ToString(Culture)).PadRight(TotalWidth, ' ')); Builder.Append("║\n║"); Builder.Append((" " + Translations.GetInterfaceString("log_rating") + " " + Translations.GetInterfaceString("rating_" + index.ToString(Culture)) + " (" + (100.0 * ratio).ToString("0.00") + "%)").PadRight(TotalWidth, ' ')); Builder.Append("║\n"); } } { // top border row Builder.Append('╠'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('╤'); } Builder.Append('═', Widths[j] + 2); } Builder.Append("╣\n"); } for (int i = 0; i < Lines.Length; i++) { // center border row if (i != 0) { Builder.Append('╟'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('┼'); } Builder.Append('─', Widths[j] + 2); } Builder.Append("╢\n"); } // cell content Builder.Append('║'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('│'); } Builder.Append(' '); if (i != 0 & j <= 3) { Builder.Append(Lines[i][j].PadLeft(Widths[j], ' ')); } else { Builder.Append(Lines[i][j].PadRight(Widths[j], ' ')); } Builder.Append(' '); } Builder.Append("║\n"); } { // bottom border row Builder.Append('╚'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('╧'); } Builder.Append('═', Widths[j] + 2); } Builder.Append('╝'); } System.IO.File.WriteAllText(File, Builder.ToString(), new System.Text.UTF8Encoding(true)); }
internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (Train == null) { return; } if (Train.RouteLimits == null) { Train.RouteLimits = new double[] { }; } if (Direction < 0) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { int n = Train.RouteLimits.Length; if (n > 0) { Array.Resize <double>(ref Train.RouteLimits, n - 1); Train.CurrentRouteLimit = double.PositiveInfinity; for (int i = 0; i < n - 1; i++) { if (Train.RouteLimits[i] < Train.CurrentRouteLimit) { Train.CurrentRouteLimit = Train.RouteLimits[i]; } } } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { int n = Train.RouteLimits.Length; Array.Resize <double>(ref Train.RouteLimits, n + 1); for (int i = n; i > 0; i--) { Train.RouteLimits[i] = Train.RouteLimits[i - 1]; } Train.RouteLimits[0] = this.PreviousSpeedLimit; } } else if (Direction > 0) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { int n = Train.RouteLimits.Length; Array.Resize <double>(ref Train.RouteLimits, n + 1); Train.RouteLimits[n] = this.NextSpeedLimit; if (this.NextSpeedLimit < Train.CurrentRouteLimit) { Train.CurrentRouteLimit = this.NextSpeedLimit; } if (Train.Specs.CurrentAverageSpeed > this.NextSpeedLimit) { Game.AddMessage(Translations.GetInterfaceString("message_route_overspeed"), MessageManager.MessageDependency.RouteLimit, Interface.GameMode.Normal, MessageColor.Orange, double.PositiveInfinity, null); } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { int n = Train.RouteLimits.Length; if (n > 0) { Train.CurrentRouteLimit = double.PositiveInfinity; for (int i = 0; i < n - 1; i++) { Train.RouteLimits[i] = Train.RouteLimits[i + 1]; if (Train.RouteLimits[i] < Train.CurrentRouteLimit) { Train.CurrentRouteLimit = Train.RouteLimits[i]; } } Array.Resize <double>(ref Train.RouteLimits, n - 1); } } } }
/// <summary> /// Launches the calibration wizard to guess the button indices used by the adapter. /// </summary> internal static void Calibrate() { string[] input = { "SELECT", "START", "A", "B", "C", Translations.QuickReferences.HandleEmergency, Translations.QuickReferences.HandleBrake + "6", Translations.QuickReferences.HandleBrake + "5", Translations.QuickReferences.HandleBrake + "4", Translations.QuickReferences.HandleBrake + "8", Translations.QuickReferences.HandlePower + "5", Translations.QuickReferences.HandlePowerNull, Translations.QuickReferences.HandlePower + "2", Translations.QuickReferences.HandlePower + "1", Translations.QuickReferences.HandlePower + "5", }; List <OpenTK.Input.ButtonState> buttonState = GetButtonsState(); List <OpenTK.Input.ButtonState> PreviousButtonState; List <HatPosition> HatPositions = GetHatPositions(); List <HatPosition> PreviousHatPositions; List <int> ignored = new List <int>(); // Button calibration for (int i = 0; i < 5; i++) { MessageBox.Show(Translations.GetInterfaceString("denshadego_calibrate_button").Replace("[button]", input[i])); PreviousButtonState = buttonState; buttonState = GetButtonsState(); int index = GetDifferentPressedIndex(PreviousButtonState, buttonState, ignored); ignored.Add(index); switch (i) { case 0: ButtonIndex.Select = index; break; case 1: ButtonIndex.Start = index; break; case 2: ButtonIndex.A = index; break; case 3: ButtonIndex.B = index; break; case 4: ButtonIndex.C = index; break; } } // The brake handle needs to be moved to EMG to initialise properly MessageBox.Show(Translations.GetInterfaceString("denshadego_calibrate_brake").Replace("[notch]", input[5])); // Brake handle calibration for (int i = 6; i < 10; i++) { MessageBox.Show(Translations.GetInterfaceString("denshadego_calibrate_brake").Replace("[notch]", input[i])); PreviousButtonState = buttonState; buttonState = GetButtonsState(); int index = GetDifferentPressedIndex(PreviousButtonState, buttonState, ignored); ignored.Add(index); switch (i) { case 6: ButtonIndex.Brake4 = index; break; case 7: ButtonIndex.Brake1 = index; break; case 8: ButtonIndex.Brake2 = index; break; case 9: ButtonIndex.Brake3 = index; break; } } // The power handle needs to be moved to P5 and N to initialise properly MessageBox.Show(Translations.GetInterfaceString("denshadego_calibrate_power").Replace("[notch]", input[10])); MessageBox.Show(Translations.GetInterfaceString("denshadego_calibrate_power").Replace("[notch]", input[11])); // Clear previous data before calibrating the power handle ignored.Clear(); buttonState = GetButtonsState(); HatPositions = GetHatPositions(); // Power handle calibration for (int i = 12; i < 15; i++) { MessageBox.Show(Translations.GetInterfaceString("denshadego_calibrate_power").Replace("[notch]", input[i])); PreviousButtonState = buttonState; PreviousHatPositions = HatPositions; buttonState = GetButtonsState(); HatPositions = GetHatPositions(); int index = GetDifferentPressedIndex(PreviousButtonState, buttonState, ignored); ignored.Add(index); int hat = GetChangedHat(PreviousHatPositions, HatPositions); if (hat != -1 && i != 13) { // If a hat has changed, it means the converter is mapping the direction buttons UsesHat = true; HatIndex = hat; } else { UsesHat = false; } switch (i) { case 12: ButtonIndex.Power2 = index; break; case 13: ButtonIndex.Power1 = index; break; case 14: ButtonIndex.Power3 = index; break; } } }
/// <summary>Exports the current black box data to a file</summary> /// <param name="File">The file to write</param> /// <param name="Format">The format in which to write the data</param> internal static void ExportBlackBox(string File, BlackBoxFormat Format) { switch (Format) { // comma separated value case BlackBoxFormat.CommaSeparatedValue: { CultureInfo Culture = CultureInfo.InvariantCulture; System.Text.StringBuilder Builder = new System.Text.StringBuilder(); for (int i = 0; i < Game.BlackBoxEntryCount; i++) { Builder.Append(Game.BlackBoxEntries[i].Time.ToString(Culture) + ","); Builder.Append(Game.BlackBoxEntries[i].Position.ToString(Culture) + ","); Builder.Append(Game.BlackBoxEntries[i].Speed.ToString(Culture) + ","); Builder.Append(Game.BlackBoxEntries[i].Acceleration.ToString(Culture) + ","); Builder.Append(((short)Game.BlackBoxEntries[i].ReverserDriver).ToString(Culture) + ","); Builder.Append(((short)Game.BlackBoxEntries[i].ReverserSafety).ToString(Culture) + ","); Builder.Append(((short)Game.BlackBoxEntries[i].PowerDriver).ToString(Culture) + ","); Builder.Append(((short)Game.BlackBoxEntries[i].PowerSafety).ToString(Culture) + ","); Builder.Append(((short)Game.BlackBoxEntries[i].BrakeDriver).ToString(Culture) + ","); Builder.Append(((short)Game.BlackBoxEntries[i].BrakeSafety).ToString(Culture) + ","); Builder.Append(((short)Game.BlackBoxEntries[i].EventToken).ToString(Culture)); Builder.Append("\r\n"); } System.IO.File.WriteAllText(File, Builder.ToString(), new System.Text.UTF8Encoding(true)); } break; // formatted text case BlackBoxFormat.FormattedText: { CultureInfo Culture = CultureInfo.InvariantCulture; System.Text.StringBuilder Builder = new System.Text.StringBuilder(); string[][] Lines = new string[Game.BlackBoxEntryCount + 1][]; Lines[0] = new string[] { Translations.GetInterfaceString("log_time"), Translations.GetInterfaceString("log_position"), Translations.GetInterfaceString("log_speed"), Translations.GetInterfaceString("log_acceleration"), Translations.GetInterfaceString("log_reverser"), Translations.GetInterfaceString("log_power"), Translations.GetInterfaceString("log_brake"), Translations.GetInterfaceString("log_event"), }; int Columns = Lines[0].Length; for (int i = 0; i < Game.BlackBoxEntryCount; i++) { int j = i + 1; Lines[j] = new string[Columns]; { double x = Game.BlackBoxEntries[i].Time; int h = (int)Math.Floor(x / 3600.0); x -= (double)h * 3600.0; int m = (int)Math.Floor(x / 60.0); x -= (double)m * 60.0; int s = (int)Math.Floor(x); x -= (double)s; int n = (int)Math.Floor(1000.0 * x); Lines[j][0] = h.ToString("00", Culture) + ":" + m.ToString("00", Culture) + ":" + s.ToString("00", Culture) + ":" + n.ToString("000", Culture); } Lines[j][1] = Game.BlackBoxEntries[i].Position.ToString("0.000", Culture); Lines[j][2] = Game.BlackBoxEntries[i].Speed.ToString("0.0000", Culture); Lines[j][3] = Game.BlackBoxEntries[i].Acceleration.ToString("0.0000", Culture); { string[] reverser = new string[2]; for (int k = 0; k < 2; k++) { short r = k == 0 ? Game.BlackBoxEntries[i].ReverserDriver : Game.BlackBoxEntries[i].ReverserSafety; switch (r) { case -1: reverser[k] = Translations.QuickReferences.HandleBackward; break; case 0: reverser[k] = Translations.QuickReferences.HandleNeutral; break; case 1: reverser[k] = Translations.QuickReferences.HandleForward; break; default: reverser[k] = r.ToString(Culture); break; } } Lines[j][4] = reverser[0] + " → " + reverser[1]; } { string[] power = new string[2]; for (int k = 0; k < 2; k++) { Game.BlackBoxPower p = k == 0 ? Game.BlackBoxEntries[i].PowerDriver : Game.BlackBoxEntries[i].PowerSafety; switch (p) { case Game.BlackBoxPower.PowerNull: power[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandlePowerNull); break; default: power[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandlePower) + ((short)p).ToString(Culture); break; } } Lines[j][5] = power[0] + " → " + power[1]; } { string[] brake = new string[2]; for (int k = 0; k < 2; k++) { Game.BlackBoxBrake b = k == 0 ? Game.BlackBoxEntries[i].BrakeDriver : Game.BlackBoxEntries[i].BrakeSafety; switch (b) { case Game.BlackBoxBrake.BrakeNull: brake[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandleBrakeNull); break; case Game.BlackBoxBrake.Emergency: brake[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandleEmergency); break; case Game.BlackBoxBrake.HoldBrake: brake[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandleHoldBrake); break; case Game.BlackBoxBrake.Release: brake[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandleRelease); break; case Game.BlackBoxBrake.Lap: brake[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandleLap); break; case Game.BlackBoxBrake.Service: brake[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandleService); break; default: brake[k] = Translations.GetInterfaceString(Translations.QuickReferences.HandleBrake) + ((short)b).ToString(Culture); break; } } Lines[j][6] = brake[0] + " → " + brake[1]; } Lines[j][7] = GetBlackBoxText(Game.BlackBoxEntries[i].EventToken); } int[] Widths = new int[Columns]; for (int i = 0; i < Lines.Length; i++) { for (int j = 0; j < Columns; j++) { if (Lines[i][j].Length > Widths[j]) { Widths[j] = Lines[i][j].Length; } } } { // header rows int TotalWidth = 0; for (int j = 0; j < Columns; j++) { TotalWidth += Widths[j] + 2; } TotalWidth += Columns - 1; Builder.Append('╔'); Builder.Append('═', TotalWidth); Builder.Append("╗\r\n"); { Builder.Append('║'); Builder.Append((" " + Translations.GetInterfaceString("log_route") + " " + Game.LogRouteName).PadRight(TotalWidth, ' ')); Builder.Append("║\r\n║"); Builder.Append((" " + Translations.GetInterfaceString("log_train") + " " + Game.LogTrainName).PadRight(TotalWidth, ' ')); Builder.Append("║\r\n║"); Builder.Append((" " + Translations.GetInterfaceString("log_date") + " " + Game.LogDateTime.ToString("yyyy-MM-dd HH:mm:ss", Culture)).PadRight(TotalWidth, ' ')); Builder.Append("║\r\n"); } } { // top border row Builder.Append('╠'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('╤'); } Builder.Append('═', Widths[j] + 2); } Builder.Append("╣\r\n"); } for (int i = 0; i < Lines.Length; i++) { // center border row if (i != 0) { Builder.Append('╟'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('┼'); } Builder.Append('─', Widths[j] + 2); } Builder.Append("╢\r\n"); } // cell content Builder.Append('║'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('│'); } Builder.Append(' '); if (i != 0 & j <= 3) { Builder.Append(Lines[i][j].PadLeft(Widths[j], ' ')); } else { Builder.Append(Lines[i][j].PadRight(Widths[j], ' ')); } Builder.Append(' '); } Builder.Append("║\r\n"); } { // bottom border row Builder.Append('╚'); for (int j = 0; j < Columns; j++) { if (j != 0) { Builder.Append('╧'); } Builder.Append('═', Widths[j] + 2); } Builder.Append('╝'); } System.IO.File.WriteAllText(File, Builder.ToString(), new System.Text.UTF8Encoding(true)); } break; } }
// // DRAW LOADING SCREEN // /// <summary>Draws on OpenGL canvas the route/train loading screen</summary> internal static void DrawLoadingScreen() { // begin HACK // if (!BlendEnabled) { GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); BlendEnabled = true; } if (LightingEnabled) { GL.Disable(EnableCap.Lighting); LightingEnabled = false; } GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.PushMatrix(); // fill the screen with background colour GL.Color4(bkgR, bkgG, bkgB, bkgA); Renderer.RenderOverlaySolid(0.0, 0.0, (double)Screen.Width, (double)Screen.Height); GL.Color4(1.0f, 1.0f, 1.0f, 1.0f); // BACKGROUND IMAGE int fontHeight = (int)Fonts.SmallFont.FontSize; int logoBottom; // int versionTop; int halfWidth = Screen.Width / 2; if (TextureLoadingBkg != null) { int bkgHeight, bkgWidth; // stretch the background image to fit at least one screen dimension double ratio = (double)TextureLoadingBkg.Width / (double)TextureLoadingBkg.Height; if (Screen.Width / ratio > Screen.Height) // if screen ratio is shorter than bkg... { bkgHeight = Screen.Height; // set height to screen height bkgWidth = (int)(Screen.Height * ratio); // and scale width proprtionally } else // if screen ratio is wider than bkg... { bkgWidth = Screen.Width; // set width to screen width bkgHeight = (int)(Screen.Width / ratio); // and scale height accordingly } // draw the background image down from the top screen edge DrawRectangle(TextureLoadingBkg, new Point((Screen.Width - bkgWidth) / 2, 0), new Size(bkgWidth, bkgHeight), Color128.White); } // if the route has no custom loading image, add the openBVE logo // (the route custom image is loaded in OldParsers/CsvRwRouteParser.cs) if (!customLoadScreen) { if (TextureLogo != null) { // place the centre of the logo at from the screen top int logoTop = (int)(Screen.Height * logoCentreYFactor - TextureLogo.Height / 2.0); logoBottom = logoTop + TextureLogo.Height; DrawRectangle(TextureLogo, new Point((Screen.Width - TextureLogo.Width) / 2, logoTop), new Size(TextureLogo.Width, TextureLogo.Height), Color128.White); } } else { // if custom route image, no logo and leave a conventional black area below the potential logo } logoBottom = Screen.Height / 2; // take the height remaining below the logo and divide in 3 horiz. parts int blankHeight = (Screen.Height - logoBottom) / 3; // VERSION NUMBER // place the version above the first division int versionTop = logoBottom + blankHeight - fontHeight; DrawString(Fonts.NormalFont, "API Version: " + RAGLINKCommons.RPlatform.SettingsContent.simulatorVersion.ToString(), new Point(65, 5), TextAlignment.TopMiddle, Color128.White); // for the moment, do not show any URL; would go right below the first division // DrawString(Fonts.SmallFont, "https://sites.google.com/site/openbvesim/home", // new Point(halfWidth, versionTop + fontHeight+2), // TextAlignment.TopMiddle, Color128.White); // PROGRESS MESSAGE AND BAR // place progress bar right below the second division //int progressTop = Screen.Height - blankHeight; int progressTop = Screen.Height - 6; //int progressWidth = Screen.Width - progrMargin * 2; int progressWidth = Screen.Width; double routeProgress = Math.Max(0.0, Math.Min(1.0, Loading.RouteProgress)); double trainProgress = Math.Max(0.0, Math.Min(1.0, Loading.TrainProgress)); // sum of route progress and train progress arrives up to 2.0: // => times 50.0 to convert to % double percent = 50.0 * (routeProgress + trainProgress); string percStr = percent.ToString("0") + "%"; // draw progress message right above the second division string text = Translations.GetInterfaceString( routeProgress < 1.0 ? "loading_loading_route" : (trainProgress < 1.0 ? "loading_loading_train" : "message_loading")) + " (" + percStr + ")"; DrawString(Fonts.NormalFont, text, new Point(halfWidth, progressTop - fontHeight - 8), TextAlignment.TopMiddle, Color128.White); // progress frame //DrawRectangle(null, new Point(progrMargin-progrBorder, progressTop-progrBorder), // new Size(progressWidth+progrBorder*2, fontHeight+6), Color128.White); // progress bar DrawRectangle(null, new Point(0, progressTop), new Size(progressWidth * (int)percent / 100, fontHeight + 4), ColourProgressBar); // progress percent //DrawString(Fonts.SmallFont, percStr, new Point(halfWidth, progressTop), // TextAlignment.TopMiddle, Color128.Black); GL.PopMatrix(); }
// get control details private string GetControlDetails(int Index) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; string Separator = Translations.GetInterfaceString("controls_assignment_separator"); if (Interface.CurrentControls[Index].Method == Interface.ControlMethod.Keyboard) { string t = Translations.GetInterfaceString("controls_assignment_keyboard") + Separator; if ((Interface.CurrentControls[Index].Modifier & Interface.KeyboardModifier.Shift) != 0) { t += Translations.GetInterfaceString("controls_assignment_keyboard_shift"); } if ((Interface.CurrentControls[Index].Modifier & Interface.KeyboardModifier.Ctrl) != 0) { t += Translations.GetInterfaceString("controls_assignment_keyboard_ctrl"); } if ((Interface.CurrentControls[Index].Modifier & Interface.KeyboardModifier.Alt) != 0) { t += Translations.GetInterfaceString("controls_assignment_keyboard_alt"); } int j; for (j = 0; j < 133; j++) { //OpenTK key description if (Interface.CurrentControls[Index].Key != Key.Unknown) { for (int k = 0; k < Translations.TranslatedKeys.Length; k++) { if (Interface.CurrentControls[Index].Key == Translations.TranslatedKeys[k].Key) { t += Translations.TranslatedKeys[k].Description; return(t); } } t += Interface.CurrentControls[Index].Key; return(t); } } if (j == 133) { t += "{" + Interface.CurrentControls[Index].Element.ToString(Culture) + "}"; } return(t); } if (Interface.CurrentControls[Index].Method == Interface.ControlMethod.Joystick) { string t = Translations.GetInterfaceString("controls_assignment_joystick").Replace("[index]", (Interface.CurrentControls[Index].Device + 1).ToString(Culture)); switch (Interface.CurrentControls[Index].Component) { case Interface.JoystickComponent.Axis: t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_axis").Replace("[index]", (Interface.CurrentControls[Index].Element + 1).ToString(Culture)); if (Interface.CurrentControls[Index].Direction == -1) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_axis_negative"); } else if (Interface.CurrentControls[Index].Direction == 1) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_axis_positive"); } else { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_axis_invalid"); } break; case Interface.JoystickComponent.Button: t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_button").Replace("[index]", (Interface.CurrentControls[Index].Element + 1).ToString(Culture)); break; case Interface.JoystickComponent.Hat: t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat").Replace("[index]", (Interface.CurrentControls[Index].Element + 1).ToString(Culture)); if (Interface.CurrentControls[Index].Direction == (int)HatPosition.Left) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_left"); } else if (Interface.CurrentControls[Index].Direction == (int)HatPosition.UpLeft) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_upleft"); } else if (Interface.CurrentControls[Index].Direction == (int)HatPosition.Up) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_up"); } else if (Interface.CurrentControls[Index].Direction == (int)HatPosition.UpRight) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_upright"); } else if (Interface.CurrentControls[Index].Direction == (int)HatPosition.Right) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_right"); } else if (Interface.CurrentControls[Index].Direction == (int)HatPosition.DownRight) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_downright"); } else if (Interface.CurrentControls[Index].Direction == (int)HatPosition.Down) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_down"); } else if (Interface.CurrentControls[Index].Direction == (int)HatPosition.DownLeft) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_downleft"); } else { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_hat_invalid"); } break; } return(t); } if (Interface.CurrentControls[Index].Method == Interface.ControlMethod.RailDriver) { string t = "RailDriver"; switch (Interface.CurrentControls[Index].Component) { case Interface.JoystickComponent.Axis: switch (Interface.CurrentControls[Index].Element) { case 0: t += Separator + "Reverser"; break; case 1: t += Separator + "Combined Power / Brake"; break; case 2: t += Separator + "Auto-Brake"; break; case 3: t += Separator + "Independant Brake"; break; case 4: t += Separator + "Bail-Off"; break; case 5: t += Separator + "Wiper Switch"; break; case 6: t += Separator + "Light Switch"; break; } if (Interface.CurrentControls[Index].Direction == -1) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_axis_negative"); } else if (Interface.CurrentControls[Index].Direction == 1) { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_axis_positive"); } else { t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_axis_invalid"); } break; case Interface.JoystickComponent.Button: t += Separator + Translations.GetInterfaceString("controls_assignment_joystick_button").Replace("[index]", (Interface.CurrentControls[Index].Element + 1).ToString(Culture)); break; } return(t); } return(Translations.GetInterfaceString("controls_assignment_invalid")); }
/// <summary>Attempts to load and parse the current train's panel configuration file.</summary> /// <param name="Train">The train</param> /// <param name="Encoding">The selected train encoding</param> internal void ParsePanelConfig(TrainBase Train, Encoding Encoding) { Train.Cars[Train.DriverCar].CarSections = new CarSection[1]; Train.Cars[Train.DriverCar].CarSections[0] = new CarSection(currentHost, ObjectType.Overlay, true); string File = Path.CombineFile(Train.TrainFolder, "panel.xml"); if (!System.IO.File.Exists(File)) { //Try animated variant too File = Path.CombineFile(Train.TrainFolder, "panel.animated.xml"); } if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); try { /* * First load the XML. We use this to determine * whether this is a 2D or a 3D animated panel */ XDocument CurrentXML = XDocument.Load(File, LoadOptions.SetLineInfo); // Check for null if (CurrentXML.Root != null) { IEnumerable <XElement> DocumentElements = CurrentXML.Root.Elements("PanelAnimated"); if (DocumentElements.Any()) { PanelAnimatedXmlParser.ParsePanelAnimatedXml(System.IO.Path.GetFileName(File), Train, Train.DriverCar); if (Train.Cars[Train.DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D) { Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable; } return; } DocumentElements = CurrentXML.Root.Elements("Panel"); if (DocumentElements.Any()) { PanelXmlParser.ParsePanelXml(System.IO.Path.GetFileName(File), Train, Train.DriverCar); Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; return; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.xml"); currentHost.ReportProblem(ProblemType.InvalidData, currentError); Cancel = true; return; } currentHost.AddMessage(MessageType.Error, false, "The panel.xml file " + File + " failed to load. Falling back to legacy panel."); } else { File = Path.CombineFile(Train.TrainFolder, "panel.animated"); if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); if (System.IO.File.Exists(Path.CombineFile(Train.TrainFolder, "panel2.cfg")) || System.IO.File.Exists(Path.CombineFile(Train.TrainFolder, "panel.cfg"))) { FileSystem.AppendToLogFile("INFO: This train contains both a 2D and a 3D panel. The 3D panel will always take precedence"); } UnifiedObject currentObject; currentHost.LoadObject(File, Encoding, out currentObject); var a = currentObject as AnimatedObjectCollection; if (a != null) { //HACK: If a == null , loading our animated object completely failed (Missing objects?). Fallback to trying the panel2.cfg try { for (int i = 0; i < a.Objects.Length; i++) { currentHost.CreateDynamicObject(ref a.Objects[i].internalObject); } Train.Cars[Train.DriverCar].CarSections[0].Groups[0].Elements = a.Objects; if (Train.Cars[Train.DriverCar].CameraRestrictionMode != CameraRestrictionMode.Restricted3D) { Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.NotAvailable; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable; } return; } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.animated"); currentHost.ReportProblem(ProblemType.InvalidData, currentError); Cancel = true; return; } } currentHost.AddMessage(MessageType.Error, false, "The panel.animated file " + File + " failed to load. Falling back to 2D panel."); } } var Panel2 = false; try { File = Path.CombineFile(Train.TrainFolder, "panel2.cfg"); if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); Panel2 = true; Panel2CfgParser.ParsePanel2Config("panel2.cfg", Train.TrainFolder, Train.Cars[Train.DriverCar]); Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; } else { File = Path.CombineFile(Train.TrainFolder, "panel.cfg"); if (System.IO.File.Exists(File)) { FileSystem.AppendToLogFile("Loading train panel: " + File); PanelCfgParser.ParsePanelConfig(Train.TrainFolder, Encoding, Train.Cars[Train.DriverCar]); Train.Cars[Train.DriverCar].CameraRestrictionMode = CameraRestrictionMode.On; Renderer.Camera.CurrentRestriction = CameraRestrictionMode.On; } else { Renderer.Camera.CurrentRestriction = CameraRestrictionMode.NotAvailable; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", Panel2 ? "panel2.cfg" : "panel.cfg"); currentHost.ReportProblem(ProblemType.InvalidData, currentError); Cancel = true; } }
private FormMain() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false; this.Text = Translations.GetInterfaceString("program_title"); }
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); } } }
internal Lamp(LampType Type) { this.Type = Type; switch (Type) { case LampType.None: this.Text = null; break; case LampType.Ats: this.Text = Translations.GetInterfaceString("lamps_ats"); break; case LampType.AtsOperation: this.Text = Translations.GetInterfaceString("lamps_atsoperation"); break; case LampType.AtsPPower: this.Text = Translations.GetInterfaceString("lamps_atsppower"); break; case LampType.AtsPPattern: this.Text = Translations.GetInterfaceString("lamps_atsppattern"); break; case LampType.AtsPBrakeOverride: this.Text = Translations.GetInterfaceString("lamps_atspbrakeoverride"); break; case LampType.AtsPBrakeOperation: this.Text = Translations.GetInterfaceString("lamps_atspbrakeoperation"); break; case LampType.AtsP: this.Text = Translations.GetInterfaceString("lamps_atsp"); break; case LampType.AtsPFailure: this.Text = Translations.GetInterfaceString("lamps_atspfailure"); break; case LampType.Atc: this.Text = Translations.GetInterfaceString("lamps_atc"); break; case LampType.AtcPower: this.Text = Translations.GetInterfaceString("lamps_atcpower"); break; case LampType.AtcUse: this.Text = Translations.GetInterfaceString("lamps_atcuse"); break; case LampType.AtcEmergency: this.Text = Translations.GetInterfaceString("lamps_atcemergency"); break; case LampType.Eb: this.Text = Translations.GetInterfaceString("lamps_eb"); break; case LampType.ConstSpeed: this.Text = Translations.GetInterfaceString("lamps_constspeed"); break; default: this.Text = "TEXT"; break; } OpenGlFont font = Fonts.NormalFont; for (int i = 0; i < HUD.CurrentHudElements.Length; i++) { if (HUD.CurrentHudElements[i].Subject.Equals("ats", StringComparison.OrdinalIgnoreCase)) { font = HUD.CurrentHudElements[i].Font; break; } } System.Drawing.Size size = font.MeasureString(this.Text); this.Width = size.Width; this.Height = size.Height; }
private void paintImage() { switch (calibrationStage) { case 0: pictureBox1.Image = main; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_start"); break; case 1: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(210, 130, 80, 145)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_down.png")), 234, 284); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_a"); break; case 2: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(210, 130, 80, 145)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_up.png")), 234, 84); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_b"); break; case 3: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(290, 130, 90, 145)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_down.png")), 314, 284); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_c"); break; case 4: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(290, 130, 90, 145)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_up.png")), 314, 84); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_d"); break; case 5: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(450, 130, 80, 165)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_down.png")), 470, 304); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_e"); break; case 6: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(450, 130, 80, 165)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_up.png")), 470, 79); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_f"); break; case 7: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(610, 130, 75, 165)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_down.png")), 630, 304); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_g"); break; case 8: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(610, 130, 75, 165)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_up.png")), 630, 79); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_h"); break; case 9: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(610, 130, 75, 165)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_left.png")), 560, 175); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_i"); break; case 10: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(610, 130, 75, 165)); graphics.DrawImage(ImageExtensions.FromFile(OpenBveApi.Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\arrow_right.png")), 690, 175); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_j"); break; case 11: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(715, 100, 55, 75)); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_k"); break; case 12: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(715, 100, 55, 75)); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_l"); break; case 13: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(715, 210, 55, 75)); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_m"); break; case 14: Modified = new Bitmap(main); using (var graphics = System.Drawing.Graphics.FromImage(Modified)) { graphics.DrawRectangle(new Pen(Color.Blue, 3.0f), new Rectangle(715, 210, 55, 75)); } pictureBox1.Image = Modified; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_n"); break; case 15: pictureBox1.Image = main; labelCalibrationText.Text = Translations.GetInterfaceString("raildriver_calibration_o"); buttonCalibrationNext.Text = Translations.GetInterfaceString("packages_success"); break; } }
/// <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(); } lock (Illustrations.Locker) { 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.LogMessages[i].Type == MessageType.Critical) { MessageBox.Show("A critical error has occured:\n\n" + Interface.LogMessages[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.CurrentDriverBody = new World.DriverBody(); 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.PlayerTrain.Cars.Length; c++) { TrainLength += TrainManager.PlayerTrain.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 = TrainManager.Trains[i] == TrainManager.PlayerTrain ? 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); TrainManager.Trains[i].Cars[j].Move(length); } } // 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 (TrainManager.Trains[i] == TrainManager.PlayerTrain) { 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); } } // timetable if (Timetable.DefaultTimetableDescription.Length == 0) { Timetable.DefaultTimetableDescription = Game.LogTrainName; } // initialize camera if (World.CameraRestriction == Camera.RestrictionMode.NotAvailable) { World.CameraMode = 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(Translations.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.LogMessages[i].FileNotFound) { filesNotFound++; } else if (Interface.LogMessages[i].Type == MessageType.Error) { errors++; } else if (Interface.LogMessages[i].Type == MessageType.Warning) { warnings++; } } string NotFound = null; string Messages; 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(Translations.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 = 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(); Renderer.UpdateViewport(Renderer.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; case 2: //Switch camera to track MainLoop.SaveCameraSettings(); World.CameraMode = 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(); Renderer.UpdateViewport(Renderer.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; case 3: //Switch camera to flyby MainLoop.SaveCameraSettings(); World.CameraMode = 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(); Renderer.UpdateViewport(Renderer.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; case 4: //Switch camera to flyby MainLoop.SaveCameraSettings(); World.CameraMode = 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(); Renderer.UpdateViewport(Renderer.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; } }
// attached joysticks private void pictureboxJoysticks_Paint(object sender, PaintEventArgs e) { this.DoubleBuffered = true; int device = -1; Interface.JoystickComponent component = Interface.JoystickComponent.Invalid; int element = -1; int direction = -1; Translations.CommandType type = Translations.CommandType.Digital; if (this.Tag == null & listviewControls.SelectedIndices.Count == 1) { int j = listviewControls.SelectedIndices[0]; if (Interface.CurrentControls[j].Method == Interface.ControlMethod.Joystick) { device = Interface.CurrentControls[j].Device; component = Interface.CurrentControls[j].Component; element = Interface.CurrentControls[j].Element; direction = Interface.CurrentControls[j].Direction; type = Interface.CurrentControls[j].InheritedType; } } System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; Font f = new Font(this.Font.Name, 0.875f * this.Font.Size); float x = 2.0f, y = 2.0f; float threshold = ((float)trackbarJoystickAxisThreshold.Value - (float)trackbarJoystickAxisThreshold.Minimum) / (float)(trackbarJoystickAxisThreshold.Maximum - trackbarJoystickAxisThreshold.Minimum); for (int i = 0; i < JoystickManager.AttachedJoysticks.Length; i++) { JoystickManager.AttachedJoysticks[i].Poll(); float w, h; if (JoystickImage != null) { e.Graphics.DrawImage(JoystickImage, x, y); w = (float)JoystickImage.Width; h = (float)JoystickImage.Height; if (h < 64.0f) { h = 64.0f; } } else { w = 64.0f; h = 64.0f; e.Graphics.DrawRectangle(new Pen(labelControlsTitle.BackColor), x, y, w, h); } { // joystick number e.Graphics.FillEllipse(Brushes.Gold, x + w - 16.0f, y, 16.0f, 16.0f); e.Graphics.DrawEllipse(Pens.Black, x + w - 16.0f, y, 16.0f, 16.0f); string t = (i + 1).ToString(Culture); SizeF s = e.Graphics.MeasureString(t, f); e.Graphics.DrawString(t, f, Brushes.Black, x + w - 8.0f - 0.5f * s.Width, y + 8.0f - 0.5f * s.Height); } { // joystick name e.Graphics.DrawString(JoystickManager.AttachedJoysticks[i].Name, this.Font, Brushes.Black, x + w + 8.0f, y); } if (OpenTK.Configuration.RunningOnSdl2) { //HACK: Control configuration doesn't work in-form on SDL2 string error = Translations.GetInterfaceString("errors_controls_ingame"); if (OpenTK.Configuration.RunningOnSdl2) { error = error.Replace("[platform]", "SDL2"); } e.Graphics.DrawString(error, this.Font, Brushes.Black, x + w + 8.0f, y + 30.0f); return; } float m; if (groupboxJoysticks.Enabled) { m = x; Pen p = new Pen(Color.DarkGoldenrod, 2.0f); Pen ps = new Pen(Color.Firebrick, 2.0f); { // first row float u = x + w + 8.0f; float v = y + 24.0f; float g = h - 24.0f; { // hats int n = JoystickManager.AttachedJoysticks[i].HatCount(); for (int j = 0; j < n; j++) { if (device == i & component == Interface.JoystickComponent.Hat & element == j) { e.Graphics.DrawEllipse(ps, u, v, g, g); } else { e.Graphics.DrawEllipse(p, u, v, g, g); } string t = "H" + (j + 1).ToString(Culture); SizeF s = e.Graphics.MeasureString(t, f); e.Graphics.DrawString(t, f, Brushes.Black, u + 0.5f * (g - s.Width), v + 0.5f * (g - s.Height)); JoystickHatState aa = JoystickManager.AttachedJoysticks[i].GetHat(j); HatPosition a = aa.Position; if (a != HatPosition.Centered) { double rx = 0.0; double ry = 0.0; switch (a) { case HatPosition.Up: rx = 0.0; ry = -1.0; break; case HatPosition.Down: rx = 0.0; ry = 1.0; break; case HatPosition.Left: rx = -1.0; ry = 0.0; break; case HatPosition.Right: rx = 1.0; ry = 0.0; break; case HatPosition.UpLeft: rx = -1.0; ry = -1.0; break; case HatPosition.UpRight: rx = 1.0; ry = -1.0; break; case HatPosition.DownLeft: rx = -1.0; ry = 1.0; break; case HatPosition.DownRight: rx = 1.0; ry = 1.0; break; } double rt = rx * rx + ry * ry; rt = 1.0 / Math.Sqrt(rt); rx *= rt; ry *= rt; float dx = (float)(0.5 * rx * (g - 8.0)); float dy = (float)(0.5 * ry * (g - 8.0)); e.Graphics.FillEllipse(Brushes.White, u + 0.5f * g + dx - 4.0f, v + 0.5f * g + dy - 4.0f, 8.0f, 8.0f); e.Graphics.DrawEllipse(new Pen(Color.Firebrick, 2.0f), u + 0.5f * g + dx - 4.0f, v + 0.5f * g + dy - 4.0f, 8.0f, 8.0f); } if (device == i & component == Interface.JoystickComponent.Hat & element == j) { double rx = ((HatPosition)direction & HatPosition.Left) != 0 ? -1.0 : ((HatPosition)direction & HatPosition.Right) != 0 ? 1.0 : 0.0; double ry = ((HatPosition)direction & HatPosition.Up) != 0 ? -1.0 : ((HatPosition)direction & HatPosition.Down) != 0 ? 1.0 : 0.0; double rt = rx * rx + ry * ry; rt = 1.0 / Math.Sqrt(rt); rx *= rt; ry *= rt; float dx = (float)(0.5 * rx * (g - 8.0)); float dy = (float)(0.5 * ry * (g - 8.0)); e.Graphics.FillEllipse(Brushes.Firebrick, u + 0.5f * g + dx - 2.0f, v + 0.5f * g + dy - 2.0f, 4.0f, 4.0f); } u += g + 8.0f; } } if (u > m) { m = u; } } { // second row float u = x; float v = y + h + 8.0f; { // axes int n = JoystickManager.AttachedJoysticks[i].AxisCount(); float g = (float)pictureboxJoysticks.ClientRectangle.Height - v - 2.0f; for (int j = 0; j < n; j++) { float r = (float)JoystickManager.AttachedJoysticks[i].GetAxis(j); float r0 = r < 0.0f ? r : 0.0f; float r1 = r > 0.0f ? r : 0.0f; if ((float)Math.Abs((double)r) < threshold) { e.Graphics.FillRectangle(Brushes.RosyBrown, u, v + 0.5f * g - 0.5f * r1 * g, 16.0f, 0.5f * g * (r1 - r0)); } else { e.Graphics.FillRectangle(Brushes.Firebrick, u, v + 0.5f * g - 0.5f * r1 * g, 16.0f, 0.5f * g * (r1 - r0)); } if (device == i & component == Interface.JoystickComponent.Axis & element == j) { if (direction == -1 & type != Translations.CommandType.AnalogFull) { e.Graphics.DrawRectangle(p, u, v, 16.0f, g); e.Graphics.DrawRectangle(ps, u, v + 0.5f * g, 16.0f, 0.5f * g); } else if (direction == 1 & type != Translations.CommandType.AnalogFull) { e.Graphics.DrawRectangle(p, u, v, 16.0f, g); e.Graphics.DrawRectangle(ps, u, v, 16.0f, 0.5f * g); } else { e.Graphics.DrawRectangle(ps, u, v, 16.0f, g); } } else { e.Graphics.DrawRectangle(p, u, v, 16.0f, g); } e.Graphics.DrawLine(p, u, v + (0.5f - 0.5f * threshold) * g, u + 16.0f, v + (0.5f - 0.5f * threshold) * g); e.Graphics.DrawLine(p, u, v + (0.5f + 0.5f * threshold) * g, u + 16.0f, v + (0.5f + 0.5f * threshold) * g); string t = "A" + (j + 1).ToString(Culture); SizeF s = e.Graphics.MeasureString(t, f); e.Graphics.DrawString(t, f, Brushes.Black, u + 0.5f * (16.0f - s.Width), v + g - s.Height - 2.0f); u += 24.0f; } } { // buttons int n = JoystickManager.AttachedJoysticks[i].ButtonCount(); float g = (float)0.5f * (pictureboxJoysticks.ClientRectangle.Height - v - 10.0f); for (int j = 0; j < n; j++) { bool q = JoystickManager.AttachedJoysticks[i].GetButton(j) != 0; float dv = (float)(j & 1) * (g + 8.0f); if (q) { e.Graphics.FillRectangle(Brushes.Firebrick, u, v + dv, g, g); } if (device == i & component == Interface.JoystickComponent.Button & element == j) { e.Graphics.DrawRectangle(ps, u, v + dv, g, g); } else { e.Graphics.DrawRectangle(p, u, v + dv, g, g); } string t = "B" + (j + 1).ToString(Culture); SizeF s = e.Graphics.MeasureString(t, f); e.Graphics.DrawString(t, f, Brushes.Black, u + 0.5f * (g - s.Width), v + dv + 0.5f * (g - s.Height)); if ((j & 1) != 0 | j == n - 1) { u += g + 8.0f; } } } if (u > m) { m = u; } } } else { m = x + w + 64.0f; } x = m + 8.0f; } }
/// <summary>Is called once by the main renderer loop, in order to render all overlays shown on the screen</summary> /// <param name="TimeElapsed">The time elapsed since the last call to this function</param> internal void Render(double TimeElapsed) { //Initialize openGL renderer.SetBlendFunc(); GL.Enable(EnableCap.Blend); renderer.PushMatrix(MatrixMode.Projection); Matrix4D.CreateOrthographicOffCenter(0.0f, renderer.Screen.Width, renderer.Screen.Height, 0.0f, -1.0f, 1.0f, out renderer.CurrentProjectionMatrix); renderer.PushMatrix(MatrixMode.Modelview); renderer.CurrentViewMatrix = Matrix4D.Identity; //Check which overlays to show switch (renderer.CurrentOutputMode) { case OutputMode.Default: //Route info overlay (if selected) Game.routeInfoOverlay.Show(); //HUD foreach (HUD.Element element in HUD.CurrentHudElements) { switch (element.Subject.ToLowerInvariant()) { case "messages": RenderGameMessages(element, TimeElapsed); break; case "scoremessages": RenderScoreMessages(element, TimeElapsed); break; case "ats": RenderATSLamps(element, TimeElapsed); break; default: RenderHUDElement(element, TimeElapsed); break; } } //Marker textures if (Interface.CurrentOptions.GameMode != GameMode.Expert) { double y = 8.0; foreach (Texture t in renderer.Marker.MarkerTextures) { if (Program.CurrentHost.LoadTexture(t, OpenGlTextureWrapMode.ClampClamp)) { double w = t.Width; double h = t.Height; renderer.Rectangle.Draw(t, new OpenBveApi.Math.Vector2(renderer.Screen.Width - w - 8.0, y), new Vector2(w, h), Color128.White); y += h + 8.0; } } } //Timetable overlay //NOTE: Only affects auto-generated timetable, possibly change this inconsistant behaviour if (Program.Renderer.CurrentTimetable == DisplayedTimetable.Default) { // default if (Program.CurrentHost.LoadTexture(Timetable.DefaultTimetableTexture, OpenGlTextureWrapMode.ClampClamp)) { int w = Timetable.DefaultTimetableTexture.Width; int h = Timetable.DefaultTimetableTexture.Height; renderer.Rectangle.Draw(Timetable.DefaultTimetableTexture, new OpenBveApi.Math.Vector2(renderer.Screen.Width - w, Timetable.DefaultTimetablePosition), new Vector2(w, h), Color128.White); } } else if (Program.Renderer.CurrentTimetable == DisplayedTimetable.Custom & Timetable.CustomObjectsUsed == 0) { // custom if (Program.CurrentHost.LoadTexture(Timetable.CurrentCustomTimetableDaytimeTexture, OpenGlTextureWrapMode.ClampClamp)) { int w = Timetable.CurrentCustomTimetableDaytimeTexture.Width; int h = Timetable.CurrentCustomTimetableDaytimeTexture.Height; renderer.Rectangle.Draw(Timetable.CurrentCustomTimetableDaytimeTexture, new OpenBveApi.Math.Vector2(renderer.Screen.Width - w, Timetable.CustomTimetablePosition), new Vector2(w, h), Color128.White); } if (Program.CurrentHost.LoadTexture(Timetable.CurrentCustomTimetableDaytimeTexture, OpenGlTextureWrapMode.ClampClamp)) { int w = Timetable.CurrentCustomTimetableDaytimeTexture.Width; int h = Timetable.CurrentCustomTimetableDaytimeTexture.Height; float alpha; if (Timetable.CurrentCustomTimetableDaytimeTexture != null) { double t = (TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].TrackPosition - TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Brightness.PreviousTrackPosition) / (TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Brightness.NextTrackPosition - TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Brightness.PreviousTrackPosition); alpha = (float)((1.0 - t) * TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Brightness.PreviousBrightness + t * TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].Brightness.NextBrightness); } else { alpha = 1.0f; } renderer.Rectangle.Draw(Timetable.CurrentCustomTimetableDaytimeTexture, new OpenBveApi.Math.Vector2(renderer.Screen.Width - w, Timetable.CustomTimetablePosition), new Vector2(w, h), new Color128(1.0f, 1.0f, 1.0f, alpha)); } } break; case OutputMode.Debug: RenderDebugOverlays(); break; case OutputMode.DebugATS: RenderATSDebugOverlay(); break; } // air brake debug output if (Interface.CurrentOptions.GameMode != GameMode.Expert & renderer.OptionBrakeSystems) { RenderBrakeSystemDebug(); } switch (Program.Renderer.CurrentInterface) { case InterfaceType.Pause: { //If paused, fade out the screen & write PAUSE renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(renderer.Screen.Width, renderer.Screen.Height), new Color128(0.0f, 0.0f, 0.0f, 0.5f)); renderer.OpenGlString.Draw(renderer.Fonts.VeryLargeFont, Translations.GetInterfaceString("menu_pause_title"), new Point(renderer.Screen.Width / 2, renderer.Screen.Height / 2), TextAlignment.CenterMiddle, Color128.White, true); if (Interface.CurrentOptions.ScreenReaderAvailable && !PauseAnnounced) { if (!Tolk.Output(Translations.GetInterfaceString("menu_pause_title"))) { Interface.CurrentOptions.ScreenReaderAvailable = false; } PauseAnnounced = true; } break; } case InterfaceType.Menu: Game.Menu.Draw(); PauseAnnounced = false; break; default: PauseAnnounced = false; break; } //Fade to black on change ends if (TrainManager.PlayerTrain != null) { if (TrainManager.PlayerTrain.Station >= 0 && Program.CurrentRoute.Stations[TrainManager.PlayerTrain.Station].Type == StationType.ChangeEnds && TrainManager.PlayerTrain.StationState == TrainStopState.Boarding) { double time = TrainManager.PlayerTrain.StationDepartureTime - Program.CurrentRoute.SecondsSinceMidnight; if (time < 1.0) { FadeToBlackDueToChangeEnds = Math.Max(0.0, 1.0 - time); } else if (FadeToBlackDueToChangeEnds > 0.0) { FadeToBlackDueToChangeEnds -= TimeElapsed; if (FadeToBlackDueToChangeEnds < 0.0) { FadeToBlackDueToChangeEnds = 0.0; } } } else if (FadeToBlackDueToChangeEnds > 0.0) { FadeToBlackDueToChangeEnds -= TimeElapsed; if (FadeToBlackDueToChangeEnds < 0.0) { FadeToBlackDueToChangeEnds = 0.0; } } if (FadeToBlackDueToChangeEnds > 0.0 & (renderer.Camera.CurrentMode == CameraViewMode.Interior | renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead)) { renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(renderer.Screen.Width, renderer.Screen.Height), new Color128(0.0f, 0.0f, 0.0f, (float)FadeToBlackDueToChangeEnds)); } } // finalize renderer.PopMatrix(MatrixMode.Projection); renderer.PopMatrix(MatrixMode.Modelview); }
// // CREATE GRADIENT PROFILE // /// <summary>Creates the route gradient profile.</summary> /// <returns>The route gradient profile as Bitmap.</returns> /// <param name="Width">The width of the bitmap to create.</param> /// <param name="Height">The height of the bitmap to create.</param> /// <param name="inGame"><c>true</c> = bitmap for in-game overlay | <c>false</c> = for standard window.</param> public static Bitmap CreateRouteGradientProfile(int Width, int Height, bool inGame) { if (CurrentRoute.Tracks[0].Elements.Length > 36 && CurrentRoute.Stations.Length == 0) { // If we have track elements, but no stations, show a specific error message, rather // than the more generic one thrown later // NOTE: Will throw the generic error message on routes shorter than 900m with no stations throw new InvalidDataException(Translations.GetInterfaceString("errors_route_corrupt_nostations")); } // Track elements are assumed to be all of the same length, and this length // is used as measure unit, rather than computing the incremental track length // in any 'real world' unit (like m). // HORIZONTAL RANGE: find first and last used element based on stations int n, n0, n1; RouteRange(out n, out n0, out n1); // VERTICAL RANGE double y0 = double.PositiveInfinity, y1 = double.NegativeInfinity; for (int i = n0; i <= n1; i++) { double y = CurrentRoute.Tracks[0].Elements[i].WorldPosition.Y; if (y < y0) { y0 = y; } if (y > y1) { y1 = y; } } if (y0 >= y1 - 1.0) { y0 = y1 - 1.0; } // allow for some padding around actual data double ox = LeftPad, oy = TopPad; double w = (double)(Width - (LeftPad + RightPad)); double h = (double)(Height - (TopPad + BottomPad + TrackOffsPad)); // horizontal and vertical scale double nd = w / (double)(n1 - n0); double yd = h / (double)(y1 - y0); // set total bitmap track position range; used by in-game profile to place // the current position of the trains; as the train positions are known as track positions, // actual track positions are needed here, rather than indices into the track element array. double minX = CurrentRoute.Tracks[0].Elements[n0].StartingTrackPosition; double maxX = CurrentRoute.Tracks[0].Elements[n1].StartingTrackPosition; double offX = ox * (maxX - minX) / w; lastGradientMinTrack = (int)(minX - offX); lastGradientMaxTrack = (int)(maxX + offX); // BITMAP (in-game display needs transparency) Bitmap b = new Bitmap(Width, Height, inGame ? System.Drawing.Imaging.PixelFormat.Format32bppArgb : System.Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(b); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; int mode = inGame ? 1 : 0; g.Clear(mapColors[mode].background); // BELOW SEA LEVEL { double y = oy + (h - 0.5 * (double)(-CurrentRoute.Atmosphere.InitialElevation - y0) * yd); double x0 = ox - (double)(0) * nd; double x1 = ox + (double)(n1 - n0) * nd; g.FillRectangle(mapColors[mode].belowSeaFill, (float)x0, (float)y, (float)x1, (float)(oy + h) - (float)y); g.DrawLine(mapColors[mode].belowSeaBrdr, (float)x0, (float)y, (float)x1, (float)y); } // GRADIENT PROFILE { n = n1 - n0 + 1; PointF[] p = new PointF[n + 2]; p[0] = new PointF((float)ox, (float)(oy + h)); for (int i = n0; i <= n1; i++) { double x = ox + (double)(i - n0) * nd; double y = oy + (h - 0.5 * (double)(CurrentRoute.Tracks[0].Elements[i].WorldPosition.Y - y0) * yd); p[i - n0 + 1] = new PointF((float)x, (float)y); } p[n + 1] = new PointF((float)(ox + (double)(n - 1) * nd), (float)(oy + h)); g.FillPolygon(mapColors[mode].elevFill, p); for (int i = 1; i < n; i++) { g.DrawLine(mapColors[mode].elevBrdr, p[i], p[i + 1]); } g.DrawLine(mapColors[mode].elevBrdr, 0.0f, (float)(oy + h), (float)Width, (float)(oy + h)); } // STATION NAMES { Font f = new Font(FontFamily.GenericSansSerif, 12.0f, GraphicsUnit.Pixel); StringFormat m = new StringFormat(); for (int i = n0; i <= n1; i++) { for (int j = 0; j < CurrentRoute.Tracks[0].Elements[i].Events.Length; j++) { if (CurrentRoute.Tracks[0].Elements[i].Events[j] is StationStartEvent) { StationStartEvent e = (StationStartEvent)CurrentRoute.Tracks[0].Elements[i].Events[j]; if (CurrentRoute.Stations[e.StationIndex].Name != string.Empty) { bool stop = CurrentRoute.Stations[e.StationIndex].PlayerStops(); if (CurrentRoute.Stations[e.StationIndex].Name.IsJapanese()) { m.Alignment = StringAlignment.Near; m.LineAlignment = StringAlignment.Near; double x = ox + (double)(i - n0) * nd; double y = oy + (h - 0.5 * (double)(CurrentRoute.Tracks[0].Elements[i].WorldPosition.Y - y0) * yd); string t = CurrentRoute.Stations[e.StationIndex].Name; float tx = 0.0f, ty = (float)oy; for (int k = 0; k < t.Length; k++) { SizeF s = g.MeasureString(t.Substring(k, 1), f, 65536, StringFormat.GenericTypographic); if (s.Width > tx) { tx = s.Width; } } for (int k = 0; k < t.Length; k++) { g.DrawString(t.Substring(k, 1), f, stop ? mapColors[mode].actNameText : mapColors[mode].inactNameText, (float)x - 0.5f * tx, ty); SizeF s = g.MeasureString(t.Substring(k, 1), f, 65536, StringFormat.GenericTypographic); ty += s.Height; } g.DrawLine(stop ? mapColors[mode].actNameBrdr : mapColors[mode].inactNameBrdr, new PointF((float)x, ty + 4.0f), new PointF((float)x, (float)y)); } else { m.Alignment = StringAlignment.Far; m.LineAlignment = StringAlignment.Near; double x = ox + (double)(i - n0) * nd; double y = oy + (h - 0.5 * (double)(CurrentRoute.Tracks[0].Elements[i].WorldPosition.Y - y0) * yd); g.RotateTransform(-90.0f); g.TranslateTransform((float)x, (float)oy, System.Drawing.Drawing2D.MatrixOrder.Append); g.DrawString(CurrentRoute.Stations[e.StationIndex].Name, f, stop ? mapColors[mode].actNameText : mapColors[mode].inactNameText, new PointF(0.0f, -5.0f), m); g.ResetTransform(); SizeF s = g.MeasureString(CurrentRoute.Stations[e.StationIndex].Name, f); g.DrawLine(stop ? mapColors[mode].actNameBrdr : mapColors[mode].inactNameBrdr, new PointF((float)x, (float)(oy + s.Width + 4)), new PointF((float)x, (float)y)); } } } } } } // ROUTE MARKERS { Font f = new Font(FontFamily.GenericSansSerif, 10.0f, GraphicsUnit.Pixel); Font fs = new Font(FontFamily.GenericSansSerif, 9.0f, GraphicsUnit.Pixel); StringFormat m = new StringFormat { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Center }; System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; int k = TrackOffDist * n / Width; if (k == 0) { if (!inGame) { //If k is equal to zero, this generally means that the WithTrack section is missing from our routefile //Adding zero to the loop control variable will also produce an infinite loop, so that's a bad idea too throw new InvalidDataException(Translations.GetInterfaceString("errors_route_corrupt_withtrack")); } /* * A route with a single station can somehow sometimes work OK in preview but not in-game * Whilst the routefile is probably broken don't chuck the exception here as it takes down the loader */ k = 1; } for (int i = n0; i <= n1; i += k) { double x = ox + (double)(i - n0) * nd; double y = (double)(CurrentRoute.Tracks[0].Elements[i].WorldPosition.Y - y0) * yd; // track offset label if (x < w) { string t = ((int)Math.Round(CurrentRoute.Tracks[0].Elements[i].StartingTrackPosition)).ToString(Culture); g.DrawString(t + "m", f, mapColors[mode].actNameText, (float)x, (float)(oy + h + TrackOffY)); } // route height at track offset (with measure and vertical line) { y = oy + (h - 0.5 * y) + 2.0f; string t = ((int)Math.Round(CurrentRoute.Atmosphere.InitialElevation + CurrentRoute.Tracks[0].Elements[i].WorldPosition.Y)).ToString(Culture); SizeF s = g.MeasureString(t, fs); if (y < oy + h - (double)s.Width - 10.0) { g.RotateTransform(-90.0f); g.TranslateTransform((float)x, (float)y + 4.0f, System.Drawing.Drawing2D.MatrixOrder.Append); g.DrawString(t + "m", fs, mapColors[mode].actNameText, 0.0f, 0.0f, m); g.ResetTransform(); g.DrawLine(mapColors[mode].inactNameBrdr, (float)x, (float)(y + s.Width + 12.0), (float)x, (float)(oy + h)); } } } } // finalize return(b); }
/// <summary>Draws on OpenGL canvas the route/train loading screen</summary> public void DrawLoadingScreen(OpenGlFont Font, double RouteProgress, double TrainProgress) { renderer.SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); //FIXME: Remove when text switches between two renderer types GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(renderer.Screen.Width, renderer.Screen.Height), bkg); // BACKGROUND IMAGE int fontHeight = (int)Font.FontSize; int logoBottom; //int versionTop; int halfWidth = renderer.Screen.Width / 2; if (TextureLoadingBkg != null && renderer.currentHost.LoadTexture(TextureLoadingBkg, OpenGlTextureWrapMode.ClampClamp)) { int bkgHeight, bkgWidth; // stretch the background image to fit at least one screen dimension double ratio = TextureLoadingBkg.Width / (double)TextureLoadingBkg.Height; if (renderer.Screen.Width / ratio > renderer.Screen.Height) // if screen ratio is shorter than bkg... { bkgHeight = renderer.Screen.Height; // set height to screen height bkgWidth = (int)(renderer.Screen.Height * ratio); // and scale width proprtionally } else // if screen ratio is wider than bkg... { bkgWidth = renderer.Screen.Width; // set width to screen width bkgHeight = (int)(renderer.Screen.Width / ratio); // and scale height accordingly } // draw the background image down from the top screen edge renderer.Rectangle.Draw(TextureLoadingBkg, new Vector2((renderer.Screen.Width - bkgWidth) / 2.0, 0), new Vector2(bkgWidth, bkgHeight), Color128.White); } // if the route has no custom loading image, add the openBVE logo // (the route custom image is loaded in OldParsers/CsvRwRouteParser.cs) if (!customLoadScreen) { if (TextureLogo != null && renderer.currentHost.LoadTexture(TextureLogo, OpenGlTextureWrapMode.ClampClamp)) { // place the centre of the logo at from the screen top int logoTop = (int)(renderer.Screen.Height * logoCentreYFactor - TextureLogo.Height / 2.0); renderer.UnsetBlendFunc(); renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f); GL.DepthMask(true); renderer.Rectangle.Draw(TextureLogo, new Vector2((renderer.Screen.Width - TextureLogo.Width) / 2.0, logoTop), new Vector2(TextureLogo.Width, TextureLogo.Height), Color128.White); renderer.SetBlendFunc(); renderer.SetAlphaFunc(AlphaFunction.Less, 1.0f); GL.DepthMask(false); renderer.Rectangle.Draw(TextureLogo, new Vector2((renderer.Screen.Width - TextureLogo.Width) / 2.0, logoTop), new Vector2(TextureLogo.Width, TextureLogo.Height), Color128.White); renderer.SetAlphaFunc(AlphaFunction.Equal, 1.0f); } } // ReSharper disable once RedundantIfElseBlock else { // if custom route image, no logo and leave a conventional black area below the potential logo } logoBottom = renderer.Screen.Height / 2; // take the height remaining below the logo and divide in 3 horiz. parts int blankHeight = (renderer.Screen.Height - logoBottom) / 3; // VERSION NUMBER // place the version above the first division int versionTop = logoBottom + blankHeight - fontHeight; renderer.OpenGlString.Draw(Font, "Version " + ProgramVersion, new Point(halfWidth, versionTop), TextAlignment.TopMiddle, Color128.White); // for the moment, do not show any URL; would go right below the first division // DrawString(Fonts.SmallFont, "https://openbve-project.net", // new Point(halfWidth, versionTop + fontHeight+2), // TextAlignment.TopMiddle, Color128.White); // PROGRESS MESSAGE AND BAR // place progress bar right below the second division int progressTop = renderer.Screen.Height - blankHeight; int progressWidth = renderer.Screen.Width - progrMargin * 2; double routeProgress = Math.Max(0.0, Math.Min(1.0, RouteProgress)); double trainProgress = Math.Max(0.0, Math.Min(1.0, TrainProgress)); // draw progress message right above the second division string text = Translations.GetInterfaceString(routeProgress < 1.0 ? "loading_loading_route" : trainProgress < 1.0 ? "loading_loading_train" : "message_loading"); renderer.OpenGlString.Draw(Font, text, new Point(halfWidth, progressTop - fontHeight - 6), TextAlignment.TopMiddle, Color128.White); // sum of route progress and train progress arrives up to 2.0: // => times 50.0 to convert to % double percent = 50.0 * (routeProgress + trainProgress); string percStr = percent.ToString("0") + "%"; // progress frame renderer.Rectangle.Draw(null, new Vector2(progrMargin - progrBorder, progressTop - progrBorder), new Vector2(progressWidth + progrBorder * 2, fontHeight + 6), Color128.White); // progress bar renderer.Rectangle.Draw(null, new Vector2(progrMargin, progressTop), new Vector2(progressWidth * (int)percent / 100.0, fontHeight + 4), ColourProgressBar); // progress percent renderer.OpenGlString.Draw(Font, percStr, new Point(halfWidth, progressTop), TextAlignment.TopMiddle, Color128.Black); }
// --- initialization and deinitialization --- /// <summary>Initializes audio. A call to Deinitialize must be made when terminating the program.</summary> /// <returns>Whether initializing audio was successful.</returns> public void Initialize(HostInterface host, SoundRange range) { Deinitialize(); CurrentHost = host; switch (range) { case SoundRange.Low: OuterRadiusFactorMinimum = 2.0; OuterRadiusFactorMaximum = 8.0; OuterRadiusFactorMaximumSpeed = 1.0; break; case SoundRange.Medium: OuterRadiusFactorMinimum = 4.0; OuterRadiusFactorMaximum = 16.0; OuterRadiusFactorMaximumSpeed = 2.0; break; case SoundRange.High: OuterRadiusFactorMinimum = 6.0; OuterRadiusFactorMaximum = 24.0; OuterRadiusFactorMaximumSpeed = 3.0; break; } OuterRadiusFactor = Math.Sqrt(OuterRadiusFactorMinimum * OuterRadiusFactorMaximum); OuterRadiusFactorSpeed = 0.0; OpenAlDevice = Alc.OpenDevice(null); try { OpenAlMic = new AudioCapture(AudioCapture.DefaultDevice, SamplingRate, ALFormat.Mono16, BufferSize); } catch { } if (OpenAlDevice != IntPtr.Zero) { OpenAlContext = Alc.CreateContext(OpenAlDevice, (int[])null); if (OpenAlContext != ContextHandle.Zero) { Alc.MakeContextCurrent(OpenAlContext); try { AL.SpeedOfSound(343.0f); } catch { MessageBox.Show(Translations.GetInterfaceString("errors_sound_openal_version"), Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); } AL.DistanceModel(ALDistanceModel.None); return; } Alc.CloseDevice(OpenAlDevice); OpenAlDevice = IntPtr.Zero; OpenAlMic.Dispose(); OpenAlMic = null; MessageBox.Show(Translations.GetInterfaceString("errors_sound_openal_context"), Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); return; } OpenAlContext = ContextHandle.Zero; MessageBox.Show(Translations.GetInterfaceString("errors_sound_openal_device"), Translations.GetInterfaceString("program_title"), MessageBoxButtons.OK, MessageBoxIcon.Hand); }
/// <summary>Attempts to load and parse the current train's panel configuration file.</summary> /// <param name="TrainPath">The absolute on-disk path to the train folder.</param> /// <param name="Encoding">The automatically detected or manually set encoding of the panel configuration file.</param> /// <param name="Train">The base train on which to apply the panel configuration.</param> internal static void ParsePanelConfig(string TrainPath, System.Text.Encoding Encoding, Train Train) { Train.Cars[Train.DriverCar].CarSections = new CarSection[1]; Train.Cars[Train.DriverCar].CarSections[0] = new CarSection { Groups = new ElementsGroup[1] }; Train.Cars[Train.DriverCar].CarSections[0].Groups[0] = new ElementsGroup { Elements = new ObjectManager.AnimatedObject[] { }, Overlay = true }; string File = OpenBveApi.Path.CombineFile(TrainPath, "panel.xml"); if (!System.IO.File.Exists(File)) { //Try animated variant too File = OpenBveApi.Path.CombineFile(TrainPath, "panel.animated.xml"); } if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); try { /* * First load the XML. We use this to determine * whether this is a 2D or a 3D animated panel */ XDocument CurrentXML = XDocument.Load(File, LoadOptions.SetLineInfo); // Check for null if (CurrentXML.Root != null) { IEnumerable <XElement> DocumentElements = CurrentXML.Root.Elements("PanelAnimated"); if (DocumentElements.Any()) { PanelAnimatedXmlParser.ParsePanelAnimatedXml(System.IO.Path.GetFileName(File), TrainPath, Train, Train.DriverCar); Train.Cars[Train.DriverCar].CameraRestrictionMode = Camera.RestrictionMode.NotAvailable; World.CameraRestriction = Camera.RestrictionMode.NotAvailable; } DocumentElements = CurrentXML.Root.Elements("Panel"); if (DocumentElements.Any()) { PanelXmlParser.ParsePanelXml(System.IO.Path.GetFileName(File), TrainPath, Train, Train.DriverCar); Train.Cars[Train.DriverCar].CameraRestrictionMode = Camera.RestrictionMode.On; World.CameraRestriction = Camera.RestrictionMode.On; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.xml"); MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Program.RestartArguments = " "; Loading.Cancel = true; return; } if (Train.Cars[Train.DriverCar].CarSections[0].Groups[0].Elements.Any()) { World.UpdateViewingDistances(); return; } Interface.AddMessage(MessageType.Error, false, "The panel.xml file " + File + " failed to load. Falling back to legacy panel."); } else { File = OpenBveApi.Path.CombineFile(TrainPath, "panel.animated"); if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); if (System.IO.File.Exists(OpenBveApi.Path.CombineFile(TrainPath, "panel2.cfg")) || System.IO.File.Exists(OpenBveApi.Path.CombineFile(TrainPath, "panel.cfg"))) { Program.FileSystem.AppendToLogFile("INFO: This train contains both a 2D and a 3D panel. The 3D panel will always take precedence"); } ObjectManager.AnimatedObjectCollection a = AnimatedObjectParser.ReadObject(File, Encoding); if (a != null) { //HACK: If a == null , loading our animated object completely failed (Missing objects?). Fallback to trying the panel2.cfg try { for (int i = 0; i < a.Objects.Length; i++) { a.Objects[i].ObjectIndex = ObjectManager.CreateDynamicObject(); } Train.Cars[Train.DriverCar].CarSections[0].Groups[0].Elements = a.Objects; Train.Cars[Train.DriverCar].CameraRestrictionMode = Camera.RestrictionMode.NotAvailable; World.CameraRestriction = Camera.RestrictionMode.NotAvailable; World.UpdateViewingDistances(); return; } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", "panel.animated"); MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Program.RestartArguments = " "; Loading.Cancel = true; return; } } Interface.AddMessage(MessageType.Error, false, "The panel.animated file " + File + " failed to load. Falling back to 2D panel."); } } var Panel2 = false; try { File = OpenBveApi.Path.CombineFile(TrainPath, "panel2.cfg"); if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); Panel2 = true; Panel2CfgParser.ParsePanel2Config("panel2.cfg", TrainPath, Encoding, Train, Train.DriverCar); Train.Cars[Train.DriverCar].CameraRestrictionMode = Camera.RestrictionMode.On; World.CameraRestriction = Camera.RestrictionMode.On; } else { File = OpenBveApi.Path.CombineFile(TrainPath, "panel.cfg"); if (System.IO.File.Exists(File)) { Program.FileSystem.AppendToLogFile("Loading train panel: " + File); PanelCfgParser.ParsePanelConfig(TrainPath, Encoding, Train); Train.Cars[Train.DriverCar].CameraRestrictionMode = Camera.RestrictionMode.On; World.CameraRestriction = Camera.RestrictionMode.On; } else { World.CameraRestriction = Camera.RestrictionMode.NotAvailable; } } } catch { var currentError = Translations.GetInterfaceString("errors_critical_file"); currentError = currentError.Replace("[file]", Panel2 ? "panel2.cfg" : "panel.cfg"); MessageBox.Show(currentError, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Program.RestartArguments = " "; Loading.Cancel = true; } }
/// <summary>This method should be called once a frame to update the player's score</summary> /// <param name="TimeElapsed">The time elapsed since this function was last called</param> internal void Update(double TimeElapsed) { // doors { bool leftopen = false; bool rightopen = false; for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { for (int k = 0; k < TrainManager.PlayerTrain.Cars[j].Doors.Length; k++) { if (TrainManager.PlayerTrain.Cars[j].Doors[k].State != 0.0) { if (TrainManager.PlayerTrain.Cars[j].Doors[k].Direction == -1) { leftopen = true; } else if (TrainManager.PlayerTrain.Cars[j].Doors[k].Direction == 1) { rightopen = true; } } } } bool bad; if (leftopen | rightopen) { bad = true; int j = TrainManager.PlayerTrain.Station; if (j >= 0) { int p = CurrentRoute.Stations[j].GetStopIndex(TrainManager.PlayerTrain.NumberOfCars); if (p >= 0) { if (Math.Abs(TrainManager.PlayerTrain.CurrentSpeed) < 0.1) { if (leftopen == CurrentRoute.Stations[j].OpenLeftDoors & rightopen == CurrentRoute.Stations[j].OpenRightDoors) { bad = false; } } } } } else { bad = false; } if (bad) { OpenedDoorsCounter += (Math.Abs(TrainManager.PlayerTrain.CurrentSpeed) + 0.25) * TimeElapsed; } else if (OpenedDoorsCounter != 0.0) { int x = (int)Math.Ceiling(ScoreFactorOpenedDoors * OpenedDoorsCounter); this.CurrentValue += x; if (x != 0) { AddScore(x, ScoreTextToken.DoorsOpened, 5.0); } OpenedDoorsCounter = 0.0; } } // overspeed double nr = TrainManager.PlayerTrain.CurrentRouteLimit; double ns = TrainManager.PlayerTrain.CurrentSectionLimit; double n = nr < ns ? nr : ns; double a = Math.Abs(TrainManager.PlayerTrain.CurrentSpeed) - 0.277777777777778; if (a > n) { OverspeedCounter += (a - n) * TimeElapsed; } else if (OverspeedCounter != 0.0) { int x = (int)Math.Ceiling(ScoreFactorOverspeed * OverspeedCounter); this.CurrentValue += x; if (x != 0) { AddScore(x, ScoreTextToken.Overspeed, 5.0); } OverspeedCounter = 0.0; } // toppling { bool q = false; for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { if (TrainManager.PlayerTrain.Cars[j].Topples) { q = true; break; } } if (q) { TopplingCounter += TimeElapsed; } else if (TopplingCounter != 0.0) { int x = (int)Math.Ceiling(ScoreFactorToppling * TopplingCounter); this.CurrentValue += x; if (x != 0) { AddScore(x, ScoreTextToken.Toppling, 5.0); } TopplingCounter = 0.0; } } // derailment if (!Derailed) { bool q = false; for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { if (TrainManager.PlayerTrain.Cars[j].Derailed) { q = true; break; } } if (q) { int x = ScoreValueDerailment; if (this.CurrentValue > 0) { x -= this.CurrentValue; } this.CurrentValue += x; if (x != 0) { AddScore(x, ScoreTextToken.Derailed, 5.0); } Derailed = true; } } // red signal { if (TrainManager.PlayerTrain.CurrentSectionLimit == 0.0) { if (!RedSignal) { int x = ScoreValueRedSignal; this.CurrentValue += x; if (x != 0) { AddScore(x, ScoreTextToken.PassedRedSignal, 5.0); } RedSignal = true; } } else { RedSignal = false; } } // arrival { int j = TrainManager.PlayerTrain.Station; if (j >= 0 & j < CurrentRoute.Stations.Length) { if (j >= ArrivalStation & TrainManager.PlayerTrain.StationState == TrainStopState.Boarding) { if (j == 0 || CurrentRoute.Stations[j - 1].Type != StationType.ChangeEnds) { // arrival int xa = ScoreValueStationArrival; this.CurrentValue += xa; if (xa != 0) { AddScore(xa, ScoreTextToken.ArrivedAtStation, 10.0); } // early/late int xb; if (CurrentRoute.Stations[j].ArrivalTime >= 0) { double d = SecondsSinceMidnight - CurrentRoute.Stations[j].ArrivalTime; if (d >= -5.0 & d <= 0.0) { xb = ScoreValueStationPerfectTime; this.CurrentValue += xb; AddScore(xb, ScoreTextToken.PerfectTimeBonus, 10.0); } else if (d > 0.0) { xb = (int)Math.Ceiling(ScoreFactorStationLate * (d - 1.0)); this.CurrentValue += xb; if (xb != 0) { AddScore(xb, ScoreTextToken.Late, 10.0); } } else { xb = 0; } } else { xb = 0; } // position int xc; int p = CurrentRoute.Stations[j].GetStopIndex(TrainManager.PlayerTrain.NumberOfCars); if (p >= 0) { double d = TrainManager.PlayerTrain.StationDistanceToStopPoint; double r; if (d >= 0) { double t = CurrentRoute.Stations[j].Stops[p].BackwardTolerance; r = (Math.Sqrt(d * d + 1.0) - 1.0) / (Math.Sqrt(t * t + 1.0) - 1.0); } else { double t = CurrentRoute.Stations[j].Stops[p].ForwardTolerance; r = (Math.Sqrt(d * d + 1.0) - 1.0) / (Math.Sqrt(t * t + 1.0) - 1.0); } if (r < 0.01) { xc = ScoreValueStationPerfectStop; this.CurrentValue += xc; AddScore(xc, ScoreTextToken.PerfectStopBonus, 10.0); } else { if (r > 1.0) { r = 1.0; } r = (r - 0.01) * 1.01010101010101; xc = (int)Math.Ceiling(ScoreFactorStationStop * r); this.CurrentValue += xc; if (xc != 0) { AddScore(xc, ScoreTextToken.Stop, 10.0); } } } else { xc = 0; } // sum if (Interface.CurrentOptions.GameMode == GameMode.Arcade) { int xs = xa + xb + xc; AddScore("", 10.0); AddScore(xs, ScoreTextToken.Total, 10.0, false); AddScore(" ", 10.0); } // evaluation if (Interface.CurrentOptions.GameMode == GameMode.Arcade) { if (CurrentRoute.Stations[j].Type == StationType.Terminal) { double y = (double)this.CurrentValue / (double)Maximum; if (y < 0.0) { y = 0.0; } if (y > 1.0) { y = 1.0; } int k = (int)Math.Floor(y * (double)Translations.RatingsCount); if (k >= Translations.RatingsCount) { k = Translations.RatingsCount - 1; } System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; AddScore(Translations.GetInterfaceString("score_rating"), 20.0); AddScore(Translations.GetInterfaceString("rating_" + k.ToString(Culture)) + " (" + (100.0 * y).ToString("0.00", Culture) + "%)", 20.0); } } } // finalize DepartureStation = j; ArrivalStation = j + 1; } } } // departure { int j = TrainManager.PlayerTrain.Station; if (j >= 0 & j < CurrentRoute.Stations.Length & j == DepartureStation) { bool q; if (CurrentRoute.Stations[j].OpenLeftDoors | CurrentRoute.Stations[j].OpenRightDoors) { q = TrainManager.PlayerTrain.StationState == TrainStopState.Completed; } else { q = TrainManager.PlayerTrain.StationState != TrainStopState.Pending & (TrainManager.PlayerTrain.CurrentSpeed <-1.5 | TrainManager.PlayerTrain.CurrentSpeed> 1.5); } if (q) { double r = TrainManager.PlayerTrain.StationDepartureTime - SecondsSinceMidnight; if (r > 0.0) { int x = (int)Math.Ceiling(ScoreFactorStationDeparture * r); this.CurrentValue += x; if (x != 0) { AddScore(x, ScoreTextToken.PrematureDeparture, 5.0); } } DepartureStation = -1; } } } // passengers if (TrainManager.PlayerTrain.Passengers.FallenOver & PassengerTimer == 0.0) { int x = ScoreValuePassengerDiscomfort; this.CurrentValue += x; AddScore(x, ScoreTextToken.PassengerDiscomfort, 5.0); PassengerTimer = 5.0; } else { PassengerTimer -= TimeElapsed; if (PassengerTimer <= 0.0) { if (TrainManager.PlayerTrain.Passengers.FallenOver) { PassengerTimer = 5.0; } else { PassengerTimer = 0.0; } } } }
/// <summary>Loads a custom plugin for the specified train.</summary> /// <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 bool LoadCustomPlugin(string trainFolder, System.Text.Encoding encoding) { string config = OpenBveApi.Path.CombineFile(trainFolder, "ats.cfg"); if (!System.IO.File.Exists(config)) { return(false); } string Text = System.IO.File.ReadAllText(config, encoding); Text = Text.Replace("\r", "").Replace("\n", ""); string file; try { file = OpenBveApi.Path.CombineFile(trainFolder, Text); } catch { Interface.AddMessage(MessageType.Error, true, "The train plugin path was malformed in " + config); return(false); } string title = System.IO.Path.GetFileName(file); if (!System.IO.File.Exists(file)) { if (Text.EndsWith(".dll") && encoding.Equals(System.Text.Encoding.Unicode)) { // Our filename ends with .dll so probably is not mangled Unicode Interface.AddMessage(MessageType.Error, true, "The train plugin " + title + " could not be found in " + config); return(false); } // Try again with ASCII encoding Text = System.IO.File.ReadAllText(config, System.Text.Encoding.GetEncoding(1252)); Text = Text.Replace("\r", "").Replace("\n", ""); try { file = OpenBveApi.Path.CombineFile(trainFolder, Text); } catch { Interface.AddMessage(MessageType.Error, true, "The train plugin path was malformed in " + config); return(false); } title = System.IO.Path.GetFileName(file); if (!System.IO.File.Exists(file)) { // Nope, still not found Interface.AddMessage(MessageType.Error, true, "The train plugin " + title + " could not be found in " + config); return(false); } } Program.FileSystem.AppendToLogFile("Loading train plugin: " + file); bool success = LoadPlugin(file, trainFolder); if (success == false) { Loading.PluginError = Translations.GetInterfaceString("errors_plugin_failure1").Replace("[plugin]", file); } else { Program.FileSystem.AppendToLogFile("Train plugin loaded successfully."); } return(success); }
/// <summary>Renders the timetable data</summary> /// <param name="timetableTexture">The texture to create</param> internal void RenderData(ref Texture timetableTexture) { // prepare timetable int w = 384, h = 192; int offsetx = 0; int actualheight = h; float descriptionwidth = 256; float descriptionheight = 16; float stationnamewidth = 16; for (int k = 0; k < 2; k++) { Bitmap b = new Bitmap(w, h); System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(b); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; g.Clear(Color.Transparent); g.FillRectangle(Brushes.White, new RectangleF(offsetx, 0, w, actualheight)); Font f = new Font(FontFamily.GenericSansSerif, 13.0f, GraphicsUnit.Pixel); Font fs = new Font(FontFamily.GenericSansSerif, 11.0f, GraphicsUnit.Pixel); Font fss = new Font(FontFamily.GenericSansSerif, 9.0f, GraphicsUnit.Pixel); // draw timetable string t; // description float x0 = offsetx + 8; float y0 = 8; if (k == 1) { t = DefaultTimetableDescription; g.DrawString(t, f, Brushes.Black, new RectangleF(x0, 6, descriptionwidth, descriptionheight + 8)); y0 += descriptionheight + 2; } // highest speed t = Translations.GetInterfaceString("timetable_highestspeed"); SizeF s = g.MeasureString(t, fs); g.DrawString(t, fs, Brushes.Black, x0, y0); float y0a = y0 + s.Height + 2; float x1 = x0 + s.Width + 4; for (int i = 0; i < Tracks.Length; i++) { float y = y0a + 18 * i; t = Tracks[i].Speed; g.DrawString(t, f, Brushes.Black, x0, y); s = g.MeasureString(t, f); float x = x0 + s.Width + 4; if (x > x1) { x1 = x; } } g.DrawLine(Pens.LightGray, new PointF(x1 - 2, 4 + descriptionheight), new PointF(x1 - 2, y0a + 18 * Tracks.Length - 1)); // driving time t = Translations.GetInterfaceString("timetable_drivingtime"); s = g.MeasureString(t, fs); g.DrawString(t, fs, Brushes.Black, x1, y0); float x2 = x1 + s.Width + 4; for (int i = 0; i < Tracks.Length; i++) { float y = y0a + 18 * i; if (Tracks[i].Time.Hour.Length != 0) { t = Tracks[i].Time.Hour; g.DrawString(t, fss, Brushes.Black, x1, y + 2); } else { t = "0"; } s = g.MeasureString(t, fss, 9999, StringFormat.GenericTypographic); float x = x1 + s.Width - 1; if (Tracks[i].Time.Minute.Length != 0) { t = Tracks[i].Time.Minute; g.DrawString(t, fs, Brushes.Black, x, y + 2); } else { t = "00:"; } s = g.MeasureString(t, fs, 9999, StringFormat.GenericTypographic); x += s.Width + 1; t = Tracks[i].Time.Second; g.DrawString(t, fss, Brushes.Black, x, y + 2); s = g.MeasureString(t, fss, 9999, StringFormat.GenericTypographic); x += s.Width + 8; if (x > x2) { x2 = x; } } for (int i = 0; i < Tracks.Length; i++) { float y = y0a + 18 * i; g.DrawLine(Pens.LightGray, new PointF(offsetx + 4, y - 1), new PointF(x2 - 2, y - 1)); } g.DrawLine(Pens.LightGray, new PointF(x2 - 2, 4 + descriptionheight), new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1)); // station name float y2 = y0; t = Translations.GetInterfaceString("timetable_stationname"); s = g.MeasureString(t, f); g.DrawString(t, f, Brushes.Black, x2, y2); float x3 = x2 + s.Width + 4; for (int i = 0; i < Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; g.DrawLine(Pens.LightGray, new PointF(x2 - 2, y - 1), new PointF(w - 4, y - 1)); t = Stations[i].Name; if (Stations[i].NameJapanese & Stations[i].Name.Length > 1) { float[] sizes = new float[t.Length]; float totalsize = 0.0f; for (int j = 0; j < t.Length; j++) { sizes[j] = g.MeasureString(new string(t[j], 1), f, 9999, StringFormat.GenericTypographic).Width; totalsize += sizes[j]; } float space = (stationnamewidth - totalsize) / (float)(t.Length - 1); float x = 0.0f; for (int j = 0; j < t.Length; j++) { g.DrawString(new string(t[j], 1), f, Brushes.Black, x2 + x, y); x += sizes[j] + space; } } else { g.DrawString(t, f, Brushes.Black, x2, y); } s = g.MeasureString(t, f); { float x = x2 + s.Width + 4; if (x > x3) { x3 = x; } } } g.DrawLine(Pens.LightGray, new PointF(x3 - 2, 4 + descriptionheight), new PointF(x3 - 2, y0 + 18 * (Stations.Length + 1))); if (k == 0) { stationnamewidth = x3 - x2 - 6; } // arrival time t = Translations.GetInterfaceString("timetable_arrivaltime"); s = g.MeasureString(t, f); g.DrawString(t, f, Brushes.Black, x3, y2); float x4 = x3 + s.Width + 4; for (int i = 0; i < Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; if (Stations[i].Pass) { t = "00"; s = g.MeasureString(t, fs); float x = x3 + s.Width; t = " ↓"; g.DrawString(t, f, Brushes.Black, x, y); s = g.MeasureString(t, f); x += +s.Width + 4; if (x > x4) { x4 = x; } } else { if (Stations[i].Arrival.Hour.Length != 0) { t = Stations[i].Arrival.Hour; g.DrawString(t, fs, Brushes.Black, x3, y); } else { t = "00"; } s = g.MeasureString(t, fs); float x = x3 + s.Width; if (Stations[i].Arrival.Minute.Length != 0 & Stations[i].Arrival.Second.Length != 0) { t = Stations[i].Arrival.Minute + ":" + Stations[i].Arrival.Second; } else { t = ""; } g.DrawString(t, f, Brushes.Black, x, y); s = g.MeasureString(t, f); x += s.Width + 4; if (x > x4) { x4 = x; } } } g.DrawLine(Pens.LightGray, new PointF(x4 - 2, 4 + descriptionheight), new PointF(x4 - 2, y0 + 18 * (Stations.Length + 1))); // departure time t = Translations.GetInterfaceString("timetable_departuretime"); s = g.MeasureString(t, f); g.DrawString(t, f, Brushes.Black, x4, y2); float x5 = x4 + s.Width + 4; for (int i = 0; i < Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; if (Stations[i].Terminal) { t = "00"; s = g.MeasureString(t, fs); float x = x4 + s.Width; const float c0 = 4; const float c1 = 32; g.DrawLine(Pens.Black, new PointF(x + c0, y + 6), new PointF(x + c1, y + 6)); g.DrawLine(Pens.Black, new PointF(x + c0, y + 10), new PointF(x + c1, y + 10)); x += c1 + 4; if (x > x5) { x5 = x; } } else { if (Stations[i].Departure.Hour.Length != 0) { t = Stations[i].Departure.Hour; g.DrawString(t, fs, Brushes.Black, x4, y); } else { t = "00"; } s = g.MeasureString(t, fs); float x = x4 + s.Width; if (Stations[i].Departure.Minute.Length != 0 & Stations[i].Departure.Second.Length != 0) { t = Stations[i].Departure.Minute + ":" + Stations[i].Departure.Second; } else { t = ""; } g.DrawString(t, f, Brushes.Black, x, y); s = g.MeasureString(t, f); x += s.Width + 4; if (x > x5) { x5 = x; } } } for (int i = 0; i < Stations.Length; i++) { float y = y0 + 18 * (i + 1) + 2; g.DrawLine(Pens.LightGray, new PointF(x2 - 2, y - 1), new PointF(w - 4, y - 1)); } // border if (k == 1) { g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4), new PointF(offsetx + 4, y0a + 18 * Tracks.Length - 1)); g.DrawLine(Pens.Black, new PointF(offsetx + 4, y0a + 18 * Tracks.Length - 1), new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1)); g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4), new PointF(w - 4, 4)); g.DrawLine(Pens.Black, new PointF(offsetx + 4, 4 + descriptionheight), new PointF(w - 4, 4 + descriptionheight)); g.DrawLine(Pens.Black, new PointF(x2 - 2, y0 + 18 * (Stations.Length + 1)), new PointF(w - 4, y0 + 18 * (Stations.Length + 1))); g.DrawLine(Pens.Black, new PointF(w - 4, 4), new PointF(w - 4, y0 + 18 * (Stations.Length + 1))); g.DrawLine(Pens.Black, new PointF(x2 - 2, y0a + 18 * Tracks.Length - 1), new PointF(x2 - 2, y0 + 18 * (Stations.Length + 1))); } // measure w = (int)Math.Ceiling((double)(x5 + 1)); h = (int)Math.Ceiling((double)(y0 + 18 * (Stations.Length + 1) + 4)); // description if (k == 0) { t = DefaultTimetableDescription; s = g.MeasureString(t, f, w - 16); descriptionwidth = s.Width; descriptionheight = s.Height + 2; h += (int)Math.Ceiling((double)s.Height) + 4; } f.Dispose(); fs.Dispose(); fss.Dispose(); // finish if (k == 0) { // measures int nw = Program.Renderer.TextureManager.RoundUpToPowerOfTwo(w); offsetx = nw - w; w = nw; actualheight = h; h = Program.Renderer.TextureManager.RoundUpToPowerOfTwo(h); } else { // create texture g.Dispose(); timetableTexture = Program.Renderer.TextureManager.RegisterTexture(b); } } }
// load threaded private static void LoadThreaded() { try { LoadEverythingThreaded(); } catch (Exception ex) { for (int i = 0; i < Program.TrainManager.Trains.Length; i++) { if (Program.TrainManager.Trains[i] != null && Program.TrainManager.Trains[i].Plugin != null) { if (Program.TrainManager.Trains[i].Plugin.LastException != null) { Interface.AddMessage(MessageType.Critical, false, "The train plugin " + Program.TrainManager.Trains[i].Plugin.PluginTitle + " caused a critical error in the route and train loader: " + Program.TrainManager.Trains[i].Plugin.LastException.Message); CrashHandler.LoadingCrash(Program.TrainManager.Trains[i].Plugin.LastException + Environment.StackTrace, true); Program.RestartArguments = " "; Cancel = true; return; } } } if (ex is 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); } Program.RestartArguments = " "; Cancel = true; } if (JobAvailable) { Thread.Sleep(10); } Complete = true; }
/// <summary>Is called once a frame to update the station state for the given train</summary> /// <param name="Train">The train</param> /// <param name="TimeElapsed">The frame time elapsed</param> private static void UpdateTrainStation(Train Train, double TimeElapsed) { if (Train.Station >= 0) { int i = Train.Station; int n = Program.CurrentRoute.Stations[Train.Station].GetStopIndex(Train.NumberOfCars); double tf, tb; if (n >= 0) { double p0 = Train.Cars[0].FrontAxle.Follower.TrackPosition - Train.Cars[0].FrontAxle.Position + 0.5 * Train.Cars[0].Length; double p1 = Program.CurrentRoute.Stations[i].Stops[n].TrackPosition; tf = Program.CurrentRoute.Stations[i].Stops[n].ForwardTolerance; tb = Program.CurrentRoute.Stations[i].Stops[n].BackwardTolerance; Train.StationDistanceToStopPoint = p1 - p0; } else { Train.StationDistanceToStopPoint = 0.0; tf = 5.0; tb = 5.0; } if (Train.StationState == TrainStopState.Pending) { Train.StationDepartureSoundPlayed = false; if (Program.CurrentRoute.Stations[i].StopsHere(Train)) { Train.StationDepartureSoundPlayed = false; //Check whether all doors are controlled by the driver if (Train.Specs.DoorOpenMode != DoorMode.Manual) { //Check that we are not moving if (Math.Abs(Train.CurrentSpeed) < 0.1 / 3.6 & Math.Abs(Train.Specs.CurrentAverageAcceleration) < 0.1 / 3.6) { AttemptToOpenDoors(Train, i, tb, tf); } } // detect arrival if (Train.CurrentSpeed > -0.277777777777778 & Train.CurrentSpeed < 0.277777777777778) { bool left, right; if (Program.CurrentRoute.Stations[i].OpenLeftDoors) { left = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Doors[0].AnticipatedOpen) { left = true; break; } } } else { left = true; } if (Program.CurrentRoute.Stations[i].OpenRightDoors) { right = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Doors[1].AnticipatedOpen) { right = true; break; } } } else { right = true; } if (left & right) { // arrival Train.StationState = TrainStopState.Boarding; Train.SafetySystems.StationAdjust.Lit = false; Train.Specs.DoorClosureAttempted = false; Train.SafetySystems.PassAlarm.Halt(); SoundBuffer buffer = (SoundBuffer)Program.CurrentRoute.Stations[i].ArrivalSoundBuffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Program.CurrentRoute.Stations[i].SoundOrigin; Program.Sounds.PlaySound(buffer, 1.0, 1.0, pos, false); } Train.StationArrivalTime = Program.CurrentRoute.SecondsSinceMidnight; Train.StationDepartureTime = Program.CurrentRoute.Stations[i].DepartureTime - Train.TimetableDelta; if (Train.StationDepartureTime - Program.CurrentRoute.SecondsSinceMidnight < Program.CurrentRoute.Stations[i].StopTime) { Train.StationDepartureTime = Program.CurrentRoute.SecondsSinceMidnight + Program.CurrentRoute.Stations[i].StopTime; } Train.Passengers.PassengerRatio = Program.CurrentRoute.Stations[i].PassengerRatio; UpdateTrainMassFromPassengerRatio(Train); if (Train.IsPlayerTrain) { double early = 0.0; if (Program.CurrentRoute.Stations[i].ArrivalTime >= 0.0) { early = (Program.CurrentRoute.Stations[i].ArrivalTime - Train.TimetableDelta) - Train.StationArrivalTime; } string s; if (early < -1.0) { s = Translations.GetInterfaceString("message_station_arrival_late"); } else if (early > 1.0) { s = Translations.GetInterfaceString("message_station_arrival_early"); } else { s = Translations.GetInterfaceString("message_station_arrival"); } System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; TimeSpan a = TimeSpan.FromSeconds(Math.Abs(early)); string b = a.Hours.ToString("00", Culture) + ":" + a.Minutes.ToString("00", Culture) + ":" + a.Seconds.ToString("00", Culture); if (Train.StationDistanceToStopPoint < -0.1) { s += Translations.GetInterfaceString("message_delimiter") + Translations.GetInterfaceString("message_station_overrun"); } else if (Train.StationDistanceToStopPoint > 0.1) { s += Translations.GetInterfaceString("message_delimiter") + Translations.GetInterfaceString("message_station_underrun"); } double d = Math.Abs(Train.StationDistanceToStopPoint); string c = d.ToString("0.0", Culture); if (Program.CurrentRoute.Stations[i].Type == StationType.Terminal) { s += Translations.GetInterfaceString("message_delimiter") + Translations.GetInterfaceString("message_station_terminal"); } s = s.Replace("[name]", Program.CurrentRoute.Stations[i].Name); s = s.Replace("[time]", b); s = s.Replace("[difference]", c); MessageManager.AddMessage(s, MessageDependency.StationArrival, GameMode.Normal, MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 10.0, null); if (Program.CurrentRoute.Stations[i].Type == StationType.Normal) { s = Translations.GetInterfaceString("message_station_deadline"); MessageManager.AddMessage(s, MessageDependency.StationDeparture, GameMode.Normal, MessageColor.White, double.PositiveInfinity, null); } Timetable.UpdateCustomTimetable(Program.CurrentRoute.Stations[i].TimetableDaytimeTexture, Program.CurrentRoute.Stations[i].TimetableNighttimeTexture); } // schedule door locks (passengers stuck between the doors) for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Doors.Length; k++) { Train.Cars[j].Doors[k].DoorLockDuration = 0.0; if (Program.CurrentRoute.Stations[i].OpenLeftDoors & Train.Cars[j].Doors[k].Direction == -1 | Program.CurrentRoute.Stations[i].OpenRightDoors & Train.Cars[j].Doors[k].Direction == 1) { double p = 0.005 * Program.CurrentRoute.Stations[i].PassengerRatio * Program.CurrentRoute.Stations[i].PassengerRatio * Program.CurrentRoute.Stations[i].PassengerRatio * Program.CurrentRoute.Stations[i].PassengerRatio; if (Program.RandomNumberGenerator.NextDouble() < p) { /* * -- door lock at state -- * minimum: 0.2 (nearly closed) * maximum: 0.8 (nearly opened) * */ Train.Cars[j].Doors[k].DoorLockState = 0.2 + 0.6 * Program.RandomNumberGenerator.NextDouble(); /* -- waiting time -- * minimum: 2.9 s * maximum: 40.0 s * average: 7.6 s * */ p = Program.RandomNumberGenerator.NextDouble(); Train.Cars[j].Doors[k].DoorLockDuration = (50.0 - 10.0 * p) / (17.0 - 16.0 * p); } } } } } else { if (Train.SafetySystems.StationAdjust != null) { Train.SafetySystems.StationAdjust.Update(tb, tf); } } } } } else if (Train.StationState == TrainStopState.Boarding) { for (int j = 0; j < Train.Cars.Length; j++) { if (GetDoorsState(Train, j, Program.CurrentRoute.Stations[i].OpenLeftDoors, Program.CurrentRoute.Stations[i].OpenRightDoors) == (TrainDoorState.Opened | TrainDoorState.AllOpened)) { //Check whether all doors are controlled by the driver, and whether this is a non-standard station type //e.g. Change ends if (Train.Specs.DoorCloseMode != DoorMode.Manual & Program.CurrentRoute.Stations[i].Type == StationType.Normal) { AttemptToCloseDoors(Train); if (Train.Specs.DoorClosureAttempted) { if (Program.CurrentRoute.Stations[i].OpenLeftDoors && !Train.Cars[j].Doors[0].AnticipatedReopen && Program.RandomNumberGenerator.NextDouble() < Program.CurrentRoute.Stations[i].ReopenDoor) { Train.Cars[j].Doors[0].ReopenLimit = Program.RandomNumberGenerator.Next(1, Program.CurrentRoute.Stations[i].ReopenStationLimit); Train.Cars[j].Doors[0].ReopenCounter = 0; Train.Cars[j].Doors[0].InterferingObjectRate = Program.RandomNumberGenerator.Next(1, Program.CurrentRoute.Stations[i].MaxInterferingObjectRate) * 0.01; if (Train.Cars[j].Doors[0].InterferingObjectRate * Train.Cars[j].Doors[0].Width >= Train.Cars[j].Doors[0].MaxTolerance) { Train.Cars[j].Doors[0].AnticipatedReopen = true; } } if (Program.CurrentRoute.Stations[i].OpenRightDoors && !Train.Cars[j].Doors[1].AnticipatedReopen && Program.RandomNumberGenerator.NextDouble() < Program.CurrentRoute.Stations[i].ReopenDoor) { Train.Cars[j].Doors[1].ReopenLimit = Program.RandomNumberGenerator.Next(1, Program.CurrentRoute.Stations[i].ReopenStationLimit); Train.Cars[j].Doors[1].ReopenCounter = 0; Train.Cars[j].Doors[1].InterferingObjectRate = Program.RandomNumberGenerator.Next(1, Program.CurrentRoute.Stations[i].MaxInterferingObjectRate) * 0.01; if (Train.Cars[j].Doors[1].InterferingObjectRate * Train.Cars[j].Doors[1].Width >= Train.Cars[j].Doors[1].MaxTolerance) { Train.Cars[j].Doors[1].AnticipatedReopen = true; } } } } } } // detect departure bool left, right; if (!Program.CurrentRoute.Stations[i].OpenLeftDoors & !Program.CurrentRoute.Stations[i].OpenRightDoors) { left = true; right = true; } else { if (Program.CurrentRoute.Stations[i].OpenLeftDoors) { left = false; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Doors.Length; k++) { if (Train.Cars[j].Doors[k].State != 0.0) { left = true; break; } } if (left) { break; } } } else { left = false; } if (Program.CurrentRoute.Stations[i].OpenRightDoors) { right = false; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Doors.Length; k++) { if (Train.Cars[j].Doors[k].State != 0.0) { right = true; break; } } if (right) { break; } } } else { right = false; } } // departure sound if (!Train.StationDepartureSoundPlayed) { SoundBuffer buffer = (SoundBuffer)Program.CurrentRoute.Stations[i].DepartureSoundBuffer; if (buffer != null) { double dur = Program.Sounds.GetDuration(buffer); if (Program.CurrentRoute.SecondsSinceMidnight >= Train.StationDepartureTime - dur) { Program.Sounds.PlaySound(buffer, 1.0, 1.0, Program.CurrentRoute.Stations[i].SoundOrigin, false); Train.StationDepartureSoundPlayed = true; } } } for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Doors[0].AnticipatedReopen && Train.Cars[j].Doors[0].State == Train.Cars[j].Doors[0].InterferingObjectRate) { if (Train.Cars[j].Doors[0].NextReopenTime == 0.0) { Train.Cars[j].Doors[0].NextReopenTime = Program.CurrentRoute.SecondsSinceMidnight + Program.CurrentRoute.Stations[i].InterferenceInDoor; } else if (Train.Cars[j].Doors[0].ReopenCounter < Train.Cars[j].Doors[0].ReopenLimit) { if (Program.CurrentRoute.SecondsSinceMidnight >= Train.Cars[j].Doors[0].NextReopenTime) { OpenTrainDoors(Train, j, true, false); } } else { Train.Cars[j].Doors[0].AnticipatedReopen = false; } } if (Train.Cars[j].Doors[1].AnticipatedReopen && Train.Cars[j].Doors[1].State == Train.Cars[j].Doors[1].InterferingObjectRate) { if (Train.Cars[j].Doors[1].NextReopenTime == 0.0) { Train.Cars[j].Doors[1].NextReopenTime = Program.CurrentRoute.SecondsSinceMidnight + Program.CurrentRoute.Stations[i].InterferenceInDoor; } else if (Train.Cars[j].Doors[1].ReopenCounter < Train.Cars[j].Doors[1].ReopenLimit) { if (Program.CurrentRoute.SecondsSinceMidnight >= Train.Cars[j].Doors[1].NextReopenTime) { OpenTrainDoors(Train, j, false, true); } } else { Train.Cars[j].Doors[1].AnticipatedReopen = false; } } } TrainDoorState doorState = GetDoorsState(Train, Program.CurrentRoute.Stations[i].OpenLeftDoors, Program.CurrentRoute.Stations[i].OpenRightDoors); if (left | right) { /* * Assume that passengers only board at a scheduled stop * If the player has opened the doors somewhere else (lineside?) * then passengers should not be boarding */ if (doorState != TrainDoorState.AllClosed && Interface.CurrentOptions.LoadingSway) { // passengers boarding for (int j = 0; j < Train.Cars.Length; j++) { if (!Train.Cars[j].EnableLoadingSway) { continue; } double r = 2.0 * Program.CurrentRoute.Stations[i].PassengerRatio * TimeElapsed; if (r >= Program.RandomNumberGenerator.NextDouble()) { int d = (int)Math.Floor(Program.RandomNumberGenerator.NextDouble() * (double)Train.Cars[j].Doors.Length); if (Train.Cars[j].Doors[d].State == 1.0) { Train.Cars[j].Specs.CurrentRollShakeDirection += (double)Train.Cars[j].Doors[d].Direction; } } } } } if (Train.Specs.DoorCloseMode == DoorMode.Manual || doorState == TrainDoorState.None || doorState == (TrainDoorState.Closed | TrainDoorState.AllClosed) || (Program.CurrentRoute.Stations[Train.Station].Type == StationType.ChangeEnds || Program.CurrentRoute.Stations[Train.Station].Type == StationType.Jump)) { if (left | right) { // departure message if (Program.CurrentRoute.SecondsSinceMidnight > Train.StationDepartureTime && (Program.CurrentRoute.Stations[i].Type != StationType.Terminal || Train != PlayerTrain)) { Train.StationState = TrainStopState.Completed; switch (Program.CurrentRoute.Stations[i].Type) { case StationType.Normal: if (!Train.IsPlayerTrain) { break; // Only trigger messages for the player train } if (!Program.CurrentRoute.Stations[i].OpenLeftDoors & !Program.CurrentRoute.Stations[i].OpenRightDoors | Train.Specs.DoorCloseMode != DoorMode.Manual) { MessageManager.AddMessage(Translations.GetInterfaceString("message_station_depart"), MessageDependency.None, GameMode.Normal, MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); } else { MessageManager.AddMessage(Translations.GetInterfaceString("message_station_depart_closedoors"), MessageDependency.None, GameMode.Normal, MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); } break; case StationType.ChangeEnds: // Change ends always jumps to the NEXT station JumpTrain(Train, i + 1); break; case StationType.Jump: // Jumps to an arbritrary station as defined in the routefile JumpTrain(Train, Program.CurrentRoute.Stations[i].JumpIndex); break; } } } else { Train.StationState = TrainStopState.Completed; if (Train.IsPlayerTrain & Program.CurrentRoute.Stations[i].Type == StationType.Normal) { MessageManager.AddMessage(Translations.GetInterfaceString("message_station_depart"), MessageDependency.None, GameMode.Normal, MessageColor.White, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); } } } } } else { if (Train.StationState != TrainStopState.Jumping) { Train.StationState = TrainStopState.Pending; } } // automatically close doors if (Train.Specs.DoorCloseMode != DoorMode.Manual & !Train.Specs.DoorClosureAttempted) { if (Train.Station == -1 | Train.StationState == TrainStopState.Completed) { if ((GetDoorsState(Train, true, true) & TrainDoorState.AllClosed) == 0) { CloseTrainDoors(Train, true, true); Train.Specs.DoorClosureAttempted = true; } } } }
/// <summary>Changes to or from fullscreen mode.</summary> internal static void ToggleFullscreen() { Program.Renderer.Screen.Fullscreen = !Program.Renderer.Screen.Fullscreen; // begin HACK // Program.Renderer.OptionFog = false; Program.Renderer.OptionLighting = false; if (Program.Renderer.Screen.Fullscreen) { IList <DisplayResolution> resolutions = DisplayDevice.Default.AvailableResolutions; for (int i = 0; i < resolutions.Count; i++) { //Test each resolution if (resolutions[i].Width == Interface.CurrentOptions.FullscreenWidth && resolutions[i].Height == Interface.CurrentOptions.FullscreenHeight && resolutions[i].BitsPerPixel == Interface.CurrentOptions.FullscreenBits) { DisplayDevice.Default.ChangeResolution(resolutions[i]); Program.currentGameWindow.Width = resolutions[i].Width; Program.currentGameWindow.Height = resolutions[i].Height; Program.Renderer.Screen.Width = Interface.CurrentOptions.FullscreenWidth; Program.Renderer.Screen.Height = Interface.CurrentOptions.FullscreenHeight; Program.currentGameWindow.WindowState = WindowState.Fullscreen; break; } } System.Threading.Thread.Sleep(20); if (Program.currentGameWindow.WindowState != WindowState.Fullscreen) { MessageBox.Show(Translations.GetInterfaceString("errors_fullscreen_switch1") + System.Environment.NewLine + Translations.GetInterfaceString("errors_fullscreen_switch2"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Program.Renderer.Screen.Fullscreen = false; } } else { DisplayDevice.Default.RestoreResolution(); Program.currentGameWindow.WindowState = WindowState.Normal; Program.currentGameWindow.Width = Interface.CurrentOptions.WindowWidth; Program.currentGameWindow.Height = Interface.CurrentOptions.WindowHeight; Program.Renderer.Screen.Width = Interface.CurrentOptions.WindowWidth; Program.Renderer.Screen.Height = Interface.CurrentOptions.WindowHeight; } Program.Renderer.Lighting.Initialize(); Program.Renderer.UpdateViewport(ViewportChangeMode.NoChange); Program.Renderer.MotionBlur.Initialize(Interface.CurrentOptions.MotionBlur); lock (BaseRenderer.GdiPlusLock) { Timetable.CreateTimetable(); } Timetable.UpdateCustomTimetable(null, null); World.InitializeCameraRestriction(); if (Program.Renderer.OptionBackFaceCulling) { GL.Enable(EnableCap.CullFace); } else { GL.Disable(EnableCap.CullFace); } // end HACK // //Reset the camera when switching between fullscreen and windowed mode //Otherwise, if the aspect ratio changes distortion will occur until the view is changed or the camera reset if (Program.Renderer.Camera.CurrentMode == CameraViewMode.Interior | Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead) { Program.Renderer.Camera.Alignment.Position = OpenBveApi.Math.Vector3.Zero; } Program.Renderer.Camera.Alignment.Yaw = 0.0; Program.Renderer.Camera.Alignment.Pitch = 0.0; Program.Renderer.Camera.Alignment.Roll = 0.0; }
//We need to explicitly specify the default constructor public OpenBVEGame(int width, int height, GraphicsMode currentGraphicsMode, GameWindowFlags @default) : base(width, height, currentGraphicsMode, Translations.GetInterfaceString("program_title"), @default) { try { var assemblyFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); System.Drawing.Icon ico = new System.Drawing.Icon(OpenBveApi.Path.CombineFile(OpenBveApi.Path.CombineDirectory(assemblyFolder, "Data"), "icon.ico")); this.Icon = ico; } catch { } }
/// <summary>Loads the current controls from the controls.cfg file</summary> /// <param name="FileOrNull">An absolute path reference to a saved controls.cfg file, or a null reference to check the default locations</param> /// <param name="Controls">The current controls array</param> internal static void LoadControls(string FileOrNull, out Control[] Controls) { string File; bool ControlsReset = false; if (FileOrNull == null) { File = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "1.5.0/controls.cfg"); if (!System.IO.File.Exists(File)) { File = OpenBveApi.Path.CombineFile(Program.FileSystem.SettingsFolder, "controls.cfg"); } if (!System.IO.File.Exists(File)) { //Load the default key assignments if the user settings don't exist File = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Controls"), "Default keyboard assignment.controls"); if (!System.IO.File.Exists(File)) { MessageBox.Show(Translations.GetInterfaceString("errors_warning") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_missing"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Controls = new Control[0]; return; } } } else { File = FileOrNull; } Controls = new Control[256]; int Length = 0; CultureInfo Culture = CultureInfo.InvariantCulture; if (System.IO.File.Exists(File)) { string[] Lines = System.IO.File.ReadAllLines(File, new System.Text.UTF8Encoding()); for (int i = 0; i < Lines.Length; i++) { Lines[i] = Lines[i].Trim(); if (Lines[i].Length != 0 && !Lines[i].StartsWith(";", StringComparison.OrdinalIgnoreCase)) { string[] Terms = Lines[i].Split(','); for (int j = 0; j < Terms.Length; j++) { Terms[j] = Terms[j].Trim(); } if (Terms.Length >= 2) { if (Length >= Controls.Length) { Array.Resize <Control>(ref Controls, Controls.Length << 1); } int j; for (j = 0; j < Translations.CommandInfos.Length; j++) { if (string.Compare(Translations.CommandInfos[j].Name, Terms[0], StringComparison.OrdinalIgnoreCase) == 0) { break; } } if (j == Translations.CommandInfos.Length) { Controls[Length].Command = Translations.Command.None; Controls[Length].InheritedType = Translations.CommandType.Digital; Controls[Length].Method = ControlMethod.Invalid; Controls[Length].Device = -1; Controls[Length].Component = JoystickComponent.Invalid; Controls[Length].Element = -1; Controls[Length].Direction = 0; Controls[Length].Modifier = KeyboardModifier.None; Controls[Length].Option = 0; } else { Controls[Length].Command = Translations.CommandInfos[j].Command; Controls[Length].InheritedType = Translations.CommandInfos[j].Type; string Method = Terms[1].ToLowerInvariant(); bool Valid = false; if (Method == "keyboard" & Terms.Length >= 4) { Key CurrentKey; // ReSharper disable once NotAccessedVariable int SDLTest; if (int.TryParse(Terms[2], out SDLTest)) { //We've discovered a SDL keybinding is present, so reset the loading process with the default keyconfig & show an appropriate error message if (ControlsReset == false) { MessageBox.Show(Translations.GetInterfaceString("errors_controls_oldversion") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_reset"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); } var DefaultControls = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Controls"), "Default keyboard assignment.controls"); if (System.IO.File.Exists(DefaultControls)) { if (ControlsReset == false) { LoadControls(DefaultControls, out CurrentControls); ControlsReset = true; } else { MessageBox.Show(Translations.GetInterfaceString("errors_warning") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_default_oldversion"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Controls = new Control[0]; } } else { MessageBox.Show(Translations.GetInterfaceString("errors_warning") + Environment.NewLine + Translations.GetInterfaceString("errors_controls_default_missing"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); Controls = new Control[0]; } continue; } if (Enum.TryParse(Terms[2], true, out CurrentKey)) { int Modifiers; if (int.TryParse(Terms[3], NumberStyles.Integer, Culture, out Modifiers)) { Controls[Length].Method = ControlMethod.Keyboard; Controls[Length].Device = -1; Controls[Length].Component = JoystickComponent.Invalid; Controls[Length].Key = CurrentKey; Controls[Length].Direction = 0; Controls[Length].Modifier = (KeyboardModifier)Modifiers; int Option; if (Terms.Length >= 5 && int.TryParse(Terms[4], NumberStyles.Integer, Culture, out Option)) { Controls[Length].Option = Option; } Valid = true; } } } else if (Method == "joystick" & Terms.Length >= 4) { int Device; if (int.TryParse(Terms[2], NumberStyles.Integer, Culture, out Device)) { string Component = Terms[3].ToLowerInvariant(); if (Component == "axis" & Terms.Length >= 6) { int CurrentAxis; if (Int32.TryParse(Terms[4], out CurrentAxis)) { int Direction; if (int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Direction)) { Controls[Length].Method = ControlMethod.Joystick; Controls[Length].Device = Device; Controls[Length].Component = JoystickComponent.Axis; Controls[Length].Element = CurrentAxis; Controls[Length].Direction = Direction; Controls[Length].Modifier = KeyboardModifier.None; int Option; if (Terms.Length >= 7 && int.TryParse(Terms[6], NumberStyles.Integer, Culture, out Option)) { Controls[Length].Option = Option; } Valid = true; } } } else if (Component == "hat" & Terms.Length >= 6) { int CurrentHat; if (Int32.TryParse(Terms[4], out CurrentHat)) { int HatDirection; if (Int32.TryParse(Terms[5], out HatDirection)) { Controls[Length].Method = ControlMethod.Joystick; Controls[Length].Device = Device; Controls[Length].Component = JoystickComponent.Hat; Controls[Length].Element = CurrentHat; Controls[Length].Direction = HatDirection; Controls[Length].Modifier = KeyboardModifier.None; int Option; if (Terms.Length >= 7 && int.TryParse(Terms[6], NumberStyles.Integer, Culture, out Option)) { Controls[Length].Option = Option; } Valid = true; } } } else if (Component == "button" & Terms.Length >= 5) { int CurrentButton; if (Int32.TryParse(Terms[4], out CurrentButton)) { Controls[Length].Method = ControlMethod.Joystick; Controls[Length].Device = Device; Controls[Length].Component = JoystickComponent.Button; Controls[Length].Element = CurrentButton; Controls[Length].Direction = 0; Controls[Length].Modifier = KeyboardModifier.None; int Option; if (Terms.Length >= 6 && int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Option)) { Controls[Length].Option = Option; } Valid = true; } } } } else if (Method == "raildriver" & Terms.Length >= 4) { int Device; if (int.TryParse(Terms[2], NumberStyles.Integer, Culture, out Device)) { string Component = Terms[3].ToLowerInvariant(); if (Component == "axis" & Terms.Length >= 6) { int CurrentAxis; if (Int32.TryParse(Terms[4], out CurrentAxis)) { int Direction; if (int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Direction)) { Controls[Length].Method = ControlMethod.RailDriver; Controls[Length].Device = Device; Controls[Length].Component = JoystickComponent.Axis; Controls[Length].Element = CurrentAxis; Controls[Length].Direction = Direction; Controls[Length].Modifier = KeyboardModifier.None; int Option; if (Terms.Length >= 7 && int.TryParse(Terms[6], NumberStyles.Integer, Culture, out Option)) { Controls[Length].Option = Option; } Valid = true; } } } else if (Component == "button" & Terms.Length >= 5) { int CurrentButton; if (Int32.TryParse(Terms[4], out CurrentButton)) { Controls[Length].Method = ControlMethod.RailDriver; Controls[Length].Device = Device; Controls[Length].Component = JoystickComponent.Button; Controls[Length].Element = CurrentButton; Controls[Length].Direction = 0; Controls[Length].Modifier = KeyboardModifier.None; int Option; if (Terms.Length >= 6 && int.TryParse(Terms[5], NumberStyles.Integer, Culture, out Option)) { Controls[Length].Option = Option; } Valid = true; } } } } if (!Valid) { Controls[Length].Method = ControlMethod.Invalid; Controls[Length].Device = -1; Controls[Length].Component = JoystickComponent.Invalid; Controls[Length].Element = -1; Controls[Length].Direction = 0; Controls[Length].Modifier = KeyboardModifier.None; Controls[Length].Option = 0; } } Length++; } } } } Array.Resize <Control>(ref Controls, Length); }
/// <summary>Updates the physics and controls for this train</summary> /// <param name="TimeElapsed">The time elapsed</param> private void UpdatePhysicsAndControls(double TimeElapsed) { if (TimeElapsed == 0.0 || TimeElapsed > 1000) { //HACK: The physics engine really does not like update times above 1000ms //This works around a bug experienced when jumping to a station on a steep hill //causing exessive acceleration return; } // move cars for (int i = 0; i < Cars.Length; i++) { Cars[i].Move(Cars[i].CurrentSpeed * TimeElapsed); if (State == TrainState.Disposed) { return; } } // update station and doors UpdateStation(TimeElapsed); UpdateDoors(TimeElapsed); // delayed handles if (Plugin == null) { Handles.Power.Safety = Handles.Power.Driver; Handles.Brake.Safety = Handles.Brake.Driver; Handles.EmergencyBrake.Safety = Handles.EmergencyBrake.Driver; } Handles.Power.Update(); Handles.Brake.Update(); Handles.Brake.Update(); Handles.EmergencyBrake.Update(); Handles.HoldBrake.Actual = Handles.HoldBrake.Driver; // update speeds UpdateSpeeds(TimeElapsed); // Update Run and Motor sounds for (int i = 0; i < Cars.Length; i++) { Cars[i].UpdateRunSounds(TimeElapsed); Cars[i].UpdateMotorSounds(TimeElapsed); } // safety system if (!Game.MinimalisticSimulation | !IsPlayerTrain) { UpdateSafetySystem(); } { // breaker sound bool breaker; if (Cars[DriverCar].CarBrake is AutomaticAirBrake) { breaker = Handles.Reverser.Actual != 0 & Handles.Power.Safety >= 1 & Handles.Brake.Safety == (int)AirBrakeHandleState.Release & !Handles.EmergencyBrake.Safety & !Handles.HoldBrake.Actual; } else { breaker = Handles.Reverser.Actual != 0 & Handles.Power.Safety >= 1 & Handles.Brake.Safety == 0 & !Handles.EmergencyBrake.Safety & !Handles.HoldBrake.Actual; } Cars[DriverCar].Breaker.Update(breaker); } // passengers Passengers.Update(Specs.CurrentAverageAcceleration, TimeElapsed); // signals if (CurrentSectionLimit == 0.0) { if (Handles.EmergencyBrake.Driver & CurrentSpeed > -0.03 & CurrentSpeed < 0.03) { CurrentSectionLimit = 6.94444444444444; if (IsPlayerTrain) { string s = Translations.GetInterfaceString("message_signal_proceed"); double a = (3.6 * CurrentSectionLimit) * Interface.CurrentOptions.SpeedConversionFactor; s = s.Replace("[speed]", a.ToString("0", CultureInfo.InvariantCulture)); s = s.Replace("[unit]", Game.UnitOfSpeed); MessageManager.AddMessage(s, MessageDependency.None, GameMode.Normal, MessageColor.Red, Program.CurrentRoute.SecondsSinceMidnight + 5.0, null); } } } // infrequent updates InternalTimerTimeElapsed += TimeElapsed; if (InternalTimerTimeElapsed > 10.0) { InternalTimerTimeElapsed -= 10.0; Synchronize(); } }