static private PlayerStopsAtStation ( int StationIndex ) : bool | ||
StationIndex | int | |
Результат | bool |
internal override void Trigger(int Direction, EventTriggerType TriggerType, TrainManager.Train Train, int CarIndex) { if (TriggerType == EventTriggerType.FrontCarFrontAxle) { if (Direction < 0) { Train.StationFrontCar = true; } else if (Direction > 0) { Train.StationFrontCar = false; if (Train == TrainManager.PlayerTrain) { Timetable.UpdateCustomTimetable(Game.Stations[this.StationIndex].TimetableDaytimeTexture, Game.Stations[this.StationIndex].TimetableNighttimeTexture); } } } else if (TriggerType == EventTriggerType.RearCarRearAxle) { if (Direction < 0) { Train.Station = this.StationIndex; Train.StationRearCar = true; if (Train.NextStopSkipped != TrainManager.StopSkipMode.None) { Train.LastStation = this.StationIndex; } Train.NextStopSkipped = TrainManager.StopSkipMode.None; } else if (Direction > 0) { if (Train.Station == StationIndex) { if (Train == TrainManager.PlayerTrain) { if (Game.PlayerStopsAtStation(StationIndex) & TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Pending) { string s = Interface.GetInterfaceString("message_station_passed"); s = s.Replace("[name]", Game.Stations[StationIndex].Name); Game.AddMessage(s, MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.Orange, Game.SecondsSinceMidnight + 10.0, null); } else if (Game.PlayerStopsAtStation(StationIndex) & TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Boarding) { string s = Interface.GetInterfaceString("message_station_passed_boarding"); s = s.Replace("[name]", Game.Stations[StationIndex].Name); Game.AddMessage(s, MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.Red, Game.SecondsSinceMidnight + 10.0, null); } } Train.Station = -1; Train.StationRearCar = false; Train.StationState = TrainManager.TrainStopState.Pending; int d = Train.DriverCar; Sounds.StopSound(Train.Cars[d].Sounds.Halt.Source); } } } }
/// <summary>This method is called once the route and train data have been preprocessed, in order to physically setup the simulation</summary> private void SetupSimulation() { if (Loading.Cancel) { Close(); } Timetable.CreateTimetable(); //Check if any critical errors have occured during the route or train loading for (int i = 0; i < Interface.MessageCount; i++) { if (Interface.Messages[i].Type == Interface.MessageType.Critical) { MessageBox.Show("A critical error has occured:\n\n" + Interface.Messages[i].Text + "\n\nPlease inspect the error log file for further information.", "Load", MessageBoxButtons.OK, MessageBoxIcon.Hand); Close(); } } Renderer.InitializeLighting(); Game.LogRouteName = System.IO.Path.GetFileName(MainLoop.currentResult.RouteFile); Game.LogTrainName = System.IO.Path.GetFileName(MainLoop.currentResult.TrainFolder); Game.LogDateTime = DateTime.Now; if (Interface.CurrentOptions.LoadInAdvance) { Textures.LoadAllTextures(); } else { Textures.UnloadAllTextures(); } // camera ObjectManager.InitializeVisibility(); World.CameraTrackFollower.Update(0.0, true, false); World.CameraTrackFollower.Update(-0.1, true, false); World.CameraTrackFollower.Update(0.1, true, false); World.CameraTrackFollower.TriggerType = TrackManager.EventTriggerType.Camera; // starting time and track position Game.SecondsSinceMidnight = 0.0; Game.StartupTime = 0.0; int PlayerFirstStationIndex = -1; double PlayerFirstStationPosition; int os = -1; bool f = false; for (int i = 0; i < Game.Stations.Length; i++) { if (!String.IsNullOrEmpty(Game.InitialStationName)) { if (Game.InitialStationName.ToLowerInvariant() == Game.Stations[i].Name.ToLowerInvariant()) { PlayerFirstStationIndex = i; } } if (Game.Stations[i].StopMode == StationStopMode.AllStop | Game.Stations[i].StopMode == StationStopMode.PlayerStop & Game.Stations[i].Stops.Length != 0) { if (f == false) { os = i; f = true; } } } if (PlayerFirstStationIndex == -1) { PlayerFirstStationIndex = os; } { int s = Game.GetStopIndex(PlayerFirstStationIndex, TrainManager.PlayerTrain.Cars.Length); if (s >= 0) { PlayerFirstStationPosition = Game.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition; double TrainLength = 0.0; for (int c = 0; c < TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars.Length; c++) { TrainLength += TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars[c].Length; } for (int j = 0; j < Game.BufferTrackPositions.Length; j++) { if (PlayerFirstStationPosition > Game.BufferTrackPositions[j] && PlayerFirstStationPosition - TrainLength < Game.BufferTrackPositions[j]) { /* * HACK: The initial start position for the player train is stuck on a set of buffers * This means we have to make some one the fly adjustments to the first station stop position */ //Set the start position to be the buffer position plus the train length plus 1m PlayerFirstStationPosition = Game.BufferTrackPositions[j] + TrainLength + 1; //Update the station stop location if (s >= 0) { Game.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition = PlayerFirstStationPosition; } else { Game.Stations[PlayerFirstStationIndex].DefaultTrackPosition = PlayerFirstStationPosition; } break; } } } else { PlayerFirstStationPosition = Game.Stations[PlayerFirstStationIndex].DefaultTrackPosition; } if (Game.InitialStationTime != -1) { Game.SecondsSinceMidnight = Game.InitialStationTime; Game.StartupTime = Game.InitialStationTime; } else { if (Game.Stations[PlayerFirstStationIndex].ArrivalTime < 0.0) { if (Game.Stations[PlayerFirstStationIndex].DepartureTime < 0.0) { Game.SecondsSinceMidnight = 0.0; Game.StartupTime = 0.0; } else { Game.SecondsSinceMidnight = Game.Stations[PlayerFirstStationIndex].DepartureTime - Game.Stations[PlayerFirstStationIndex].StopTime; Game.StartupTime = Game.Stations[PlayerFirstStationIndex].DepartureTime - Game.Stations[PlayerFirstStationIndex].StopTime; } } else { Game.SecondsSinceMidnight = Game.Stations[PlayerFirstStationIndex].ArrivalTime; Game.StartupTime = Game.Stations[PlayerFirstStationIndex].ArrivalTime; } } } int OtherFirstStationIndex = -1; double OtherFirstStationPosition = 0.0; double OtherFirstStationTime = 0.0; for (int i = 0; i < Game.Stations.Length; i++) { if (Game.Stations[i].StopMode == StationStopMode.AllStop | Game.Stations[i].StopMode == StationStopMode.PlayerPass & Game.Stations[i].Stops.Length != 0) { OtherFirstStationIndex = i; int s = Game.GetStopIndex(i, TrainManager.PlayerTrain.Cars.Length); if (s >= 0) { OtherFirstStationPosition = Game.Stations[i].Stops[s].TrackPosition; } else { OtherFirstStationPosition = Game.Stations[i].DefaultTrackPosition; } if (Game.Stations[i].ArrivalTime < 0.0) { if (Game.Stations[i].DepartureTime < 0.0) { OtherFirstStationTime = 0.0; } else { OtherFirstStationTime = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime; } } else { OtherFirstStationTime = Game.Stations[i].ArrivalTime; } break; } } if (Game.PrecedingTrainTimeDeltas.Length != 0) { OtherFirstStationTime -= Game.PrecedingTrainTimeDeltas[Game.PrecedingTrainTimeDeltas.Length - 1]; if (OtherFirstStationTime < Game.SecondsSinceMidnight) { Game.SecondsSinceMidnight = OtherFirstStationTime; } } // initialize trains for (int i = 0; i < TrainManager.Trains.Length; i++) { TrainManager.Trains[i].Initialize(); int s = i == TrainManager.PlayerTrain.TrainIndex ? PlayerFirstStationIndex : OtherFirstStationIndex; if (s >= 0) { if (Game.Stations[s].OpenLeftDoors) { for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { TrainManager.Trains[i].Cars[j].Doors[0].AnticipatedOpen = true; } } if (Game.Stations[s].OpenRightDoors) { for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { TrainManager.Trains[i].Cars[j].Doors[1].AnticipatedOpen = true; } } } if (Game.Sections.Length != 0) { Game.Sections[0].Enter(TrainManager.Trains[i]); } for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { double length = TrainManager.Trains[i].Cars[0].Length; TrainManager.Trains[i].Cars[j].Move(-length, 0.01); TrainManager.Trains[i].Cars[j].Move(length, 0.01); } } // score Game.CurrentScore.ArrivalStation = PlayerFirstStationIndex + 1; Game.CurrentScore.DepartureStation = PlayerFirstStationIndex; Game.CurrentScore.Maximum = 0; for (int i = 0; i < Game.Stations.Length; i++) { if (i != PlayerFirstStationIndex & Game.PlayerStopsAtStation(i)) { if (i == 0 || Game.Stations[i - 1].Type != StationType.ChangeEnds) { Game.CurrentScore.Maximum += Game.ScoreValueStationArrival; } } } if (Game.CurrentScore.Maximum <= 0) { Game.CurrentScore.Maximum = Game.ScoreValueStationArrival; } // signals if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } // move train in position for (int i = 0; i < TrainManager.Trains.Length; i++) { double p; if (i == TrainManager.PlayerTrain.TrainIndex) { p = PlayerFirstStationPosition; } else if (TrainManager.Trains[i].State == TrainManager.TrainState.Bogus) { p = Game.BogusPretrainInstructions[0].TrackPosition; TrainManager.Trains[i].AI = new Game.BogusPretrainAI(TrainManager.Trains[i]); } else { p = OtherFirstStationPosition; } for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { TrainManager.Trains[i].Cars[j].Move(p, 0.01); } } // timetable if (Timetable.DefaultTimetableDescription.Length == 0) { Timetable.DefaultTimetableDescription = Game.LogTrainName; } // initialize camera if (World.CameraRestriction == World.CameraRestrictionMode.NotAvailable) { World.CameraMode = World.CameraViewMode.InteriorLookAhead; } //Place the initial camera in the driver car TrainManager.PlayerTrain.Cars[TrainManager.PlayerTrain.DriverCar].UpdateCamera(); World.CameraTrackFollower.Update(-1.0, true, false); ObjectManager.UpdateVisibility(World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z); World.CameraSavedExterior = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-2.5, 1.5, -15.0), 0.3, -0.2, 0.0, PlayerFirstStationPosition, 1.0); World.CameraSavedTrack = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-3.0, 2.5, 0.0), 0.3, 0.0, 0.0, TrainManager.PlayerTrain.Cars[0].FrontAxle.Follower.TrackPosition - 10.0, 1.0); // signalling sections for (int i = 0; i < TrainManager.Trains.Length; i++) { int s = TrainManager.Trains[i].CurrentSectionIndex; Game.Sections[s].Enter(TrainManager.Trains[i]); } if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } // fast-forward until start time { Game.MinimalisticSimulation = true; const double w = 0.25; double u = Game.StartupTime - Game.SecondsSinceMidnight; if (u > 0) { while (true) { double v = u < w ? u : w; u -= v; Game.SecondsSinceMidnight += v; TrainManager.UpdateTrains(v); if (u <= 0.0) { break; } TotalTimeElapsedForSectionUpdate += v; if (TotalTimeElapsedForSectionUpdate >= 1.0) { if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } TotalTimeElapsedForSectionUpdate = 0.0; } } } Game.MinimalisticSimulation = false; } // animated objects ObjectManager.UpdateAnimatedWorldObjects(0.0, true); TrainManager.UpdateTrainObjects(0.0, true); //HACK: This function calls a single update on all objects attached to the player's train // but ignores any specified damping so that all needles etc. are in the correct place // for the first frame, rather than spinning wildly to get to the starting point. TrainManager.PlayerTrain.UpdateCabObjects(); // timetable if (TrainManager.PlayerTrain.Station >= 0) { Timetable.UpdateCustomTimetable(Game.Stations[TrainManager.PlayerTrain.Station].TimetableDaytimeTexture, Game.Stations[TrainManager.PlayerTrain.Station].TimetableNighttimeTexture); if (Timetable.CustomObjectsUsed != 0 & Timetable.CustomTimetableAvailable && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.AutoGenerated && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.None) { Timetable.CurrentTimetable = Timetable.TimetableState.Custom; } } //Create AI driver for the player train if specified via the commmand line if (Game.InitialAIDriver == true) { TrainManager.PlayerTrain.AI = new Game.SimpleHumanDriverAI(TrainManager.PlayerTrain); if (TrainManager.PlayerTrain.Plugin != null && !TrainManager.PlayerTrain.Plugin.SupportsAI) { Game.AddMessage(Interface.GetInterfaceString("notification_aiunable"), MessageManager.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.White, Game.SecondsSinceMidnight + 10.0, null); } } // warnings / errors if (Interface.MessageCount != 0) { int filesNotFound = 0; int errors = 0; int warnings = 0; for (int i = 0; i < Interface.MessageCount; i++) { if (Interface.Messages[i].FileNotFound) { filesNotFound++; } else if (Interface.Messages[i].Type == Interface.MessageType.Error) { errors++; } else if (Interface.Messages[i].Type == Interface.MessageType.Warning) { warnings++; } } string NotFound = null; string Messages = null; if (filesNotFound != 0) { NotFound = filesNotFound.ToString() + " file(s) not found"; Game.AddMessage(NotFound, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null); } if (errors != 0 & warnings != 0) { Messages = errors.ToString() + " error(s), " + warnings.ToString() + " warning(s)"; Game.AddMessage(Messages, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null); } else if (errors != 0) { Messages = errors.ToString() + " error(s)"; Game.AddMessage(Messages, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null); } else { Messages = warnings.ToString() + " warning(s)"; Game.AddMessage(Messages, MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 10.0, null); } Game.RouteInformation.FilesNotFound = NotFound; Game.RouteInformation.ErrorsAndWarnings = Messages; //Print the plugin error encountered (If any) for 10s //This must be done after the simulation has init, as otherwise the timeout doesn't work if (Loading.PluginError != null) { Game.AddMessage(Loading.PluginError, MessageManager.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0, null); Game.AddMessage(Interface.GetInterfaceString("errors_plugin_failure2"), MessageManager.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0, null); } } loadComplete = true; RenderRealTimeElapsed = 0.0; RenderTimeElapsed = 0.0; World.InitializeCameraRestriction(); Loading.SimulationSetup = true; switch (Game.InitialViewpoint) { case 1: //Switch camera to exterior MainLoop.SaveCameraSettings(); World.CameraMode = World.CameraViewMode.Exterior; MainLoop.RestoreCameraSettings(); for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior); } //Make bogies visible for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0); TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0); } World.CameraAlignmentDirection = new World.CameraAlignment(); World.CameraAlignmentSpeed = new World.CameraAlignment(); MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; case 2: //Switch camera to track MainLoop.SaveCameraSettings(); World.CameraMode = World.CameraViewMode.Track; MainLoop.RestoreCameraSettings(); for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior); } for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0); TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0); } World.CameraAlignmentDirection = new World.CameraAlignment(); World.CameraAlignmentSpeed = new World.CameraAlignment(); MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; case 3: //Switch camera to flyby MainLoop.SaveCameraSettings(); World.CameraMode = World.CameraViewMode.FlyBy; MainLoop.RestoreCameraSettings(); for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior); } for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0); TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0); } World.CameraAlignmentDirection = new World.CameraAlignment(); World.CameraAlignmentSpeed = new World.CameraAlignment(); MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; case 4: //Switch camera to flyby MainLoop.SaveCameraSettings(); World.CameraMode = World.CameraViewMode.FlyByZooming; MainLoop.RestoreCameraSettings(); for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].ChangeCarSection(TrainManager.CarSectionType.Exterior); } for (int j = 0; j < TrainManager.PlayerTrain.Cars.Length; j++) { TrainManager.PlayerTrain.Cars[j].FrontBogie.ChangeSection(0); TrainManager.PlayerTrain.Cars[j].RearBogie.ChangeSection(0); } World.CameraAlignmentDirection = new World.CameraAlignment(); World.CameraAlignmentSpeed = new World.CameraAlignment(); MainLoop.UpdateViewport(MainLoop.ViewPortChangeMode.NoChange); World.UpdateAbsoluteCamera(0.0); World.UpdateViewingDistances(); break; } }
// // 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> internal static Bitmap CreateRouteGradientProfile(int Width, int Height, bool inGame) { if (TrackManager.CurrentTrack.Elements.Length > 36 && Game.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 Exception(Interface.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 = TrackManager.CurrentTrack.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 = TrackManager.CurrentTrack.Elements[n0].StartingTrackPosition; double maxX = TrackManager.CurrentTrack.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)(-Game.RouteInitialElevation - 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)(TrackManager.CurrentTrack.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 < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j]; if (Game.Stations[e.StationIndex].Name != string.Empty) { bool stop = Game.PlayerStopsAtStation(e.StationIndex); if (Interface.IsJapanese(Game.Stations[e.StationIndex].Name)) { m.Alignment = StringAlignment.Near; m.LineAlignment = StringAlignment.Near; double x = ox + (double)(i - n0) * nd; double y = oy + (h - 0.5 * (double)(TrackManager.CurrentTrack.Elements[i].WorldPosition.Y - y0) * yd); string t = Game.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)(TrackManager.CurrentTrack.Elements[i].WorldPosition.Y - y0) * yd); g.RotateTransform(-90.0f); g.TranslateTransform((float)x, (float)oy, System.Drawing.Drawing2D.MatrixOrder.Append); g.DrawString(Game.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(Game.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 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 Exception(Interface.GetInterfaceString("errors_route_corrupt_withtrack")); } for (int i = n0; i <= n1; i += k) { double x = ox + (double)(i - n0) * nd; double y = (double)(TrackManager.CurrentTrack.Elements[i].WorldPosition.Y - y0) * yd; // track offset label if (x < w) { string t = ((int)Math.Round(TrackManager.CurrentTrack.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(Game.RouteInitialElevation + TrackManager.CurrentTrack.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); }
// // CREATE ROUTE MAP // /// <summary>Creates and returns the route map as Bitmap.</summary> /// <returns>The route map.</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> internal static Bitmap CreateRouteMap(int Width, int Height, bool inGame) { int n, n0, n1; RouteRange(out n, out n0, out n1); // find dimensions double x0 = double.PositiveInfinity, z0 = double.PositiveInfinity; double x1 = double.NegativeInfinity, z1 = double.NegativeInfinity; for (int i = n0; i <= n1; i++) { double x = TrackManager.CurrentTrack.Elements[i].WorldPosition.X; double z = TrackManager.CurrentTrack.Elements[i].WorldPosition.Z; if (x < x0) { x0 = x; } if (x > x1) { x1 = x; } if (z < z0) { z0 = z; } if (z > z1) { z1 = z; } } // avoid 0 or negative height or width if (x0 >= x1 - 1.0) { x0 = x1 - 1.0; } if (z0 >= z1 - 1.0) { z0 = z1 - 1.0; } // remember area occupied so far double xMin, xMax, zMin, zMax; // used to track the bitmap area actually occupied by drawings xMin = x0; xMax = x1; zMin = z1; // bitmap z goes down, while world z goes up zMax = z0; // fit route w/h ratio in image w/h ratio double wrh = (double)Width / (double)Height; if ((x1 - x0) / (z1 - z0) <= wrh) // if route ratio is taller than bitmap ratio { double dx = 0.5 * (z1 - z0) * wrh; // scale (half of) x range as much as (half of) z range double px = 0.5 * (x0 + x1); // x range mid point x0 = px - dx; // centre scaled x range around mid point x1 = px + dx; } else // if route ratio is wider than bitmap ratio { // do the opposite (scale z range on x) double dz = 0.5 * (x1 - x0) / wrh; double pz = 0.5 * (z0 + z1); z0 = pz - dz; z1 = pz + dz; } double ox = LeftPad, oy = TopPad; double w = (double)(Width - (LeftPad + RightPad)); double h = (double)(Height - (TopPad + BottomPad)); // horizontal and vertical scales double xd = w / (x1 - x0); double zd = h / (z1 - z0); // convert bitmap occupied area from world to bitmap coordinates xMin = ox + (xMin - x0) * xd; xMax = ox + (xMax - x0) * xd; zMin = oy + (z0 - zMin) * zd + h; zMax = oy + (z0 - zMax) * zd + h; // create bitmap int mode = inGame ? 1 : 0; 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; g.Clear(mapColors[mode].background); // ROUTE PATH { int start = 0; bool atc = false; n = n1 - n0 + 1; PointF[] p = new PointF[n]; for (int i = 0; i < n; i++) { double x = TrackManager.CurrentTrack.Elements[i + n0].WorldPosition.X; double z = TrackManager.CurrentTrack.Elements[i + n0].WorldPosition.Z; x = ox + (x - x0) * xd; z = oy + (z0 - z) * zd + h; p[i] = new PointF((float)x, (float)z); // ATS / ATC // for each track element, look for a StationStartEvent for (int j = 0; j < TrackManager.CurrentTrack.Elements[i + n0].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i + n0].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i + n0].Events[j]; // if StationStartEvent found, look for a change in ATS/ATC control; // if there is a change, draw all previous track elements // with colour for the previous control state if (Game.Stations[e.StationIndex].SafetySystem == Game.SafetySystem.Atc) { if (!atc) { atc = true; if (i - start - 1 > 0) { g.DrawCurve(mapColors[mode].normalMap, p, start, i - start - 1); } start = i; } } else { if (atc) { atc = false; if (i - start - 1 > 0) { g.DrawCurve(mapColors[mode].atcMap, p, start, i - start - 1); } start = i; } } break; } } } // draw all remaining track element not drawn yet DrawSegmentedCurve(g, atc ? mapColors[mode].atcMap : mapColors[mode].normalMap, p, start, n - start - 1); } // STATION ICONS for (int i = n0; i <= n1; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j]; if (Game.Stations[e.StationIndex].Name != string.Empty) { double x = TrackManager.CurrentTrack.Elements[i].WorldPosition.X; double y = TrackManager.CurrentTrack.Elements[i].WorldPosition.Z; x = ox + (x - x0) * xd; y = oy + (z0 - y) * zd + h; // station circle RectangleF r = new RectangleF((float)x - StationRadius, (float)y - StationRadius, StationDiameter, StationDiameter); bool q = Game.PlayerStopsAtStation(e.StationIndex); g.FillEllipse(q ? mapColors[mode].actStatnFill : mapColors[mode].inactStatnFill, r); g.DrawEllipse(q ? mapColors[mode].actStatnBrdr : mapColors[mode].inactStatnBrdr, r); // adjust bitmap occupied area if (r.Left < xMin) { xMin = r.Left; } if (r.Top < zMin) { zMin = r.Top; } if (r.Right > xMax) { xMax = r.Right; } if (r.Bottom > zMax) { zMax = r.Bottom; } } } } } // STATION NAMES { double wh = w * h; Font f = new Font(FontFamily.GenericSansSerif, wh < 65536.0 ? 9.0f : 10.0f, GraphicsUnit.Pixel); for (int i = n0; i <= n1; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j]; if (Game.Stations[e.StationIndex].Name != string.Empty) { double x = TrackManager.CurrentTrack.Elements[i].WorldPosition.X; double y = TrackManager.CurrentTrack.Elements[i].WorldPosition.Z; x = ox + (x - x0) * xd; y = oy + (z0 - y) * zd + h; RectangleF r = new RectangleF((float)x - StationRadius, (float)y - StationRadius, StationDiameter, StationDiameter); bool stop = Game.PlayerStopsAtStation(e.StationIndex); string t = Game.Stations[e.StationIndex].Name; SizeF m = g.MeasureString(t, f, Width, StringFormat.GenericDefault); double sx = TrackManager.CurrentTrack.Elements[i].WorldSide.X; double sz = TrackManager.CurrentTrack.Elements[i].WorldSide.Z; double xt, yt; if (Math.Sign(sx) == Math.Sign(sz)) { // descending bool o = (x - ox) * (h - y) <= (w - x) * (y - oy); if (o) { // up-right xt = x + StationTextPad; yt = y - StationTextPad - m.Height; } else { // down-left xt = x - StationTextPad - m.Width; yt = y + StationTextPad; } } else { // ascending bool o = (h - y) * (w - x) <= (x - ox) * (y - oy); if (o) { // up-left xt = x - StationTextPad - m.Width; yt = y - StationTextPad - m.Height; } else { // down-right xt = x + StationTextPad; yt = y + StationTextPad; } } // constrain text within bitmap edges (taking into account also paddings) if (xt < ox) { xt = ox; } else if (xt + m.Width > w) { xt = w - m.Width; } if (yt < oy) { yt = oy; } else if (yt + m.Height > h) { yt = h - m.Height; } r = new RectangleF((float)xt - 1.0f, (float)yt - 1.0f, m.Width + 2.0f, m.Height + 2.0f); g.FillRectangle(stop ? mapColors[mode].actNameFill : mapColors[mode].inactNameFill, r.Left, r.Top, r.Width, r.Height); g.DrawRectangle(stop ? mapColors[mode].actNameBrdr : mapColors[mode].inactNameBrdr, r.Left, r.Top, r.Width, r.Height); g.DrawString(t, f, stop ? mapColors[mode].actNameText : mapColors[mode].inactNameText, (float)xt, (float)yt); // adjust bitmap occupied area if (r.Left < xMin) { xMin = r.Left; } if (r.Top < zMin) { zMin = r.Top; } if (r.Right > xMax) { xMax = r.Right; } if (r.Bottom > zMax) { zMax = r.Bottom; } } } } } } // if in-game, trim unused parts of the bitmap if (inGame) { xMin -= LeftPad; xMax += RightPad; zMin -= TopPad; zMax += BottomPad; if (xMin < 0) { xMin = 0; } if (xMax >= Width) { xMax = Width - 1; } if (zMin < 0) { zMin = 0; } if (zMax >= Height) { zMax = Height - 1; } Bitmap nb = new Bitmap((int)(xMax - xMin + 1.0), (int)(zMax - zMin + 1.0)); // round up g = Graphics.FromImage(nb); g.DrawImage(b, (int)-xMin, (int)-zMin); // round down // set total bitmap world X and Z ranges from bitmap ranges lastRouteMinX = (int)((xMin - ox) / xd + x0); lastRouteMaxX = (int)((xMax - ox) / xd + x0); lastRouteMinZ = (int)(z0 - (zMax - oy - h) / zd); lastRouteMaxZ = (int)(z0 - (zMin - oy - h) / zd); return(nb); } //set total bitmap X and Z ranges lastRouteMinX = (int)(x0 - ox * (x1 - x0) / w); lastRouteMaxX = (int)(x1 + (Width - w - ox) * (x1 - x0) / w); lastRouteMinZ = (int)(z0 - oy * (z1 - z0) / h); lastRouteMaxZ = (int)(z1 + (Height - h - oy) * (z1 - z0) / h); return(b); }
// collect data internal static void CollectData(out Table Table) { System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; Table.Stations = new Station[16]; Table.Tracks = new Track[16]; int n = 0; double Limit = -1.0, LastLimit = 6.94444444444444; int LastArrivalHours = -1, LastDepartureHours = -1; double LastTime = -1.0; for (int i = 0; i < TrackManager.CurrentTrack.Elements.Length; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { TrackManager.StationStartEvent sse = TrackManager.CurrentTrack.Elements[i].Events[j] as TrackManager.StationStartEvent; if (sse != null && Game.Stations[sse.StationIndex].Name != string.Empty) { if (Limit == -1.0) { Limit = LastLimit; } // update station if (n == Table.Stations.Length) { Array.Resize <Station>(ref Table.Stations, Table.Stations.Length << 1); } Table.Stations[n].Name = Game.Stations[sse.StationIndex].Name; Table.Stations[n].NameJapanese = Game.Stations[sse.StationIndex].Name.IsJapanese(); Table.Stations[n].Pass = !Game.PlayerStopsAtStation(sse.StationIndex); Table.Stations[n].Terminal = Game.Stations[sse.StationIndex].Type != StationType.Normal; double x; if (Game.Stations[sse.StationIndex].ArrivalTime >= 0.0) { x = Game.Stations[sse.StationIndex].ArrivalTime; x -= 86400.0 * Math.Floor(x / 86400.0); int hours = (int)Math.Floor(x / 3600.0); x -= 3600.0 * (double)hours; int minutes = (int)Math.Floor(x / 60.0); x -= 60.0 * (double)minutes; int seconds = (int)Math.Floor(x); Table.Stations[n].Arrival.Hour = hours != LastArrivalHours?hours.ToString("00", Culture) : ""; Table.Stations[n].Arrival.Minute = minutes.ToString("00", Culture); Table.Stations[n].Arrival.Second = seconds.ToString("00", Culture); LastArrivalHours = hours; } else { Table.Stations[n].Arrival.Hour = ""; Table.Stations[n].Arrival.Minute = ""; Table.Stations[n].Arrival.Second = ""; } if (Game.Stations[sse.StationIndex].DepartureTime >= 0.0) { x = Game.Stations[sse.StationIndex].DepartureTime; x -= 86400.0 * Math.Floor(x / 86400.0); int hours = (int)Math.Floor(x / 3600.0); x -= 3600.0 * (double)hours; int minutes = (int)Math.Floor(x / 60.0); x -= 60.0 * (double)minutes; int seconds = (int)Math.Floor(x); Table.Stations[n].Departure.Hour = hours != LastDepartureHours?hours.ToString("00", Culture) : ""; Table.Stations[n].Departure.Minute = minutes.ToString("00", Culture); Table.Stations[n].Departure.Second = seconds.ToString("00", Culture); LastDepartureHours = hours; } else { Table.Stations[n].Departure.Hour = ""; Table.Stations[n].Departure.Minute = ""; Table.Stations[n].Departure.Second = ""; } // update track if (n >= 1) { int m = n - 1; if (m == Table.Tracks.Length) { Array.Resize <Track>(ref Table.Tracks, Table.Tracks.Length << 1); } // speed x = Math.Round(3.6 * Limit); Table.Tracks[m].Speed = x.ToString(Culture); // time if (LastTime >= 0.0) { if (Game.Stations[sse.StationIndex].ArrivalTime >= 0.0) { x = Game.Stations[sse.StationIndex].ArrivalTime; } else if (Game.Stations[sse.StationIndex].DepartureTime >= 0.0) { x = Game.Stations[sse.StationIndex].DepartureTime; } else { x = -1.0; } if (x >= 0.0) { x -= LastTime; int hours = (int)Math.Floor(x / 3600.0); x -= 3600.0 * (double)hours; int minutes = (int)Math.Floor(x / 60.0); x -= 60.0 * (double)minutes; int seconds = (int)Math.Floor(x); Table.Tracks[m].Time.Hour = hours != 0 ? hours.ToString("0", Culture) : ""; Table.Tracks[m].Time.Minute = minutes != 0 ? minutes.ToString("00", Culture) : ""; Table.Tracks[m].Time.Second = seconds != 0 ? seconds.ToString("00", Culture) : ""; } else { Table.Tracks[m].Time.Hour = ""; Table.Tracks[m].Time.Minute = ""; Table.Tracks[m].Time.Second = ""; } } else { Table.Tracks[m].Time.Hour = ""; Table.Tracks[m].Time.Minute = ""; Table.Tracks[m].Time.Second = ""; } } // update last data if (Game.Stations[sse.StationIndex].DepartureTime >= 0.0) { LastTime = Game.Stations[sse.StationIndex].DepartureTime; } else if (Game.Stations[sse.StationIndex].ArrivalTime >= 0.0) { LastTime = Game.Stations[sse.StationIndex].ArrivalTime; } else { LastTime = -1.0; } LastLimit = Limit; Limit = -1.0; n++; } if (n >= 1) { TrackManager.LimitChangeEvent lce = TrackManager.CurrentTrack.Elements[i].Events[j] as TrackManager.LimitChangeEvent; if (lce != null) { if (lce.NextSpeedLimit != double.PositiveInfinity & lce.NextSpeedLimit > Limit) { Limit = lce.NextSpeedLimit; } } } } } Array.Resize <Station>(ref Table.Stations, n); if (n >= 2) { Array.Resize <Track>(ref Table.Tracks, n - 1); } else { Table.Tracks = new Track[] { }; } }
/// <summary>Renders all default HUD elements</summary> /// <param name="Element">The HUD element these are to be rendererd onto</param> /// <param name="TimeElapsed">The time elapsed</param> private static void RenderHUDElement(HUD.Element Element, double TimeElapsed) { TrainManager.TrainDoorState LeftDoors = TrainManager.GetDoorsState(TrainManager.PlayerTrain, true, false); TrainManager.TrainDoorState RightDoors = TrainManager.GetDoorsState(TrainManager.PlayerTrain, false, true); System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; string Command = Element.Subject.ToLowerInvariant(); // default double w, h; if (Element.CenterMiddle.BackgroundTexture != null) { if (Textures.LoadTexture(Element.CenterMiddle.BackgroundTexture, OpenGlTextureWrapMode.ClampClamp)) { w = (double)Element.CenterMiddle.BackgroundTexture.Width; h = (double)Element.CenterMiddle.BackgroundTexture.Height; } else { w = 0.0; h = 0.0; } } else { w = 0.0; h = 0.0; } double x = Element.Alignment.X < 0 ? 0.0 : Element.Alignment.X == 0 ? 0.5 * (Screen.Width - w) : Screen.Width - w; double y = Element.Alignment.Y < 0 ? 0.0 : Element.Alignment.Y == 0 ? 0.5 * (Screen.Height - h) : Screen.Height - h; x += Element.Position.X; y += Element.Position.Y; // command const double speed = 1.0; MessageColor sc = MessageColor.None; string t; switch (Command) { case "reverser": if (TrainManager.PlayerTrain.Handles.Reverser.Driver < 0) { sc = MessageColor.Orange; if (TrainManager.PlayerTrain.ReverserDescriptions != null && TrainManager.PlayerTrain.ReverserDescriptions.Length > 2) { t = TrainManager.PlayerTrain.ReverserDescriptions[2]; } else { t = Translations.QuickReferences.HandleBackward; } } else if (TrainManager.PlayerTrain.Handles.Reverser.Driver > 0) { sc = MessageColor.Blue; if (TrainManager.PlayerTrain.ReverserDescriptions != null && TrainManager.PlayerTrain.ReverserDescriptions.Length > 0) { t = TrainManager.PlayerTrain.ReverserDescriptions[0]; } else { t = Translations.QuickReferences.HandleForward; } } else { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.ReverserDescriptions != null && TrainManager.PlayerTrain.ReverserDescriptions.Length > 1) { t = TrainManager.PlayerTrain.ReverserDescriptions[1]; } else { t = Translations.QuickReferences.HandleNeutral; } } Element.TransitionState = 0.0; break; case "power": if (TrainManager.PlayerTrain.Handles.SingleHandle) { return; } if (TrainManager.PlayerTrain.Handles.Power.Driver == 0) { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.PowerNotchDescriptions.Length > 0) { t = TrainManager.PlayerTrain.PowerNotchDescriptions[0]; } else { t = Translations.QuickReferences.HandlePowerNull; } } else { sc = MessageColor.Blue; if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.Handles.Power.Driver < TrainManager.PlayerTrain.PowerNotchDescriptions.Length) { t = TrainManager.PlayerTrain.PowerNotchDescriptions[TrainManager.PlayerTrain.Handles.Power.Driver]; } else { t = Translations.QuickReferences.HandlePower + TrainManager.PlayerTrain.Handles.Power.Driver.ToString(Culture); } } Element.TransitionState = 0.0; break; case "brake": if (TrainManager.PlayerTrain.Handles.SingleHandle) { return; } if (TrainManager.PlayerTrain.Handles.Brake is TrainManager.AirBrakeHandle) { if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver) { sc = MessageColor.Red; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 0) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[0]; } else { t = Translations.QuickReferences.HandleEmergency; } } else if (TrainManager.PlayerTrain.Handles.Brake.Driver == (int)TrainManager.AirBrakeHandleState.Release) { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1]; } else { t = Translations.QuickReferences.HandleRelease; } } else if (TrainManager.PlayerTrain.Handles.Brake.Driver == (int)TrainManager.AirBrakeHandleState.Lap) { sc = MessageColor.Blue; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 2) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[2]; } else { t = Translations.QuickReferences.HandleLap; } } else { sc = MessageColor.Orange; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 3) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[3]; } else { t = Translations.QuickReferences.HandleService; } } } else { if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver) { sc = MessageColor.Red; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 0) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[0]; } else { t = Translations.QuickReferences.HandleEmergency; } } else if (TrainManager.PlayerTrain.Handles.HoldBrake.Driver) { sc = MessageColor.Green; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 2) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[2]; } else { t = Translations.QuickReferences.HandleHoldBrake; } } else if (TrainManager.PlayerTrain.Handles.Brake.Driver == 0) { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1]; } else { t = Translations.QuickReferences.HandleBrakeNull; } } else { sc = MessageColor.Orange; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && ((TrainManager.PlayerTrain.Handles.HasHoldBrake && TrainManager.PlayerTrain.Handles.Brake.Driver + 2 < TrainManager.PlayerTrain.BrakeNotchDescriptions.Length) || (!TrainManager.PlayerTrain.Handles.HasHoldBrake && TrainManager.PlayerTrain.Handles.Brake.Driver + 1 < TrainManager.PlayerTrain.BrakeNotchDescriptions.Length))) { t = TrainManager.PlayerTrain.Handles.HasHoldBrake ? TrainManager.PlayerTrain.BrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.Brake.Driver + 2] : TrainManager.PlayerTrain.BrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.Brake.Driver + 1]; } else { t = Translations.QuickReferences.HandleBrake + TrainManager.PlayerTrain.Handles.Brake.Driver.ToString(Culture); } } } Element.TransitionState = 0.0; break; case "locobrake": if (!TrainManager.PlayerTrain.Handles.HasLocoBrake) { return; } if (TrainManager.PlayerTrain.Handles.LocoBrake is TrainManager.LocoAirBrakeHandle) { if (TrainManager.PlayerTrain.Handles.LocoBrake.Driver == (int)TrainManager.AirBrakeHandleState.Release) { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1]; } else { t = Translations.QuickReferences.HandleRelease; } } else if (TrainManager.PlayerTrain.Handles.LocoBrake.Driver == (int)TrainManager.AirBrakeHandleState.Lap) { sc = MessageColor.Blue; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 2) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[2]; } else { t = Translations.QuickReferences.HandleLap; } } else { sc = MessageColor.Orange; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 3) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[3]; } else { t = Translations.QuickReferences.HandleService; } } } else { if (TrainManager.PlayerTrain.Handles.LocoBrake.Driver == 0) { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.LocoBrakeNotchDescriptions != null && TrainManager.PlayerTrain.LocoBrakeNotchDescriptions.Length > 1) { t = TrainManager.PlayerTrain.LocoBrakeNotchDescriptions[1]; } else { t = Translations.QuickReferences.HandleBrakeNull; } } else { sc = MessageColor.Orange; if (TrainManager.PlayerTrain.LocoBrakeNotchDescriptions != null && TrainManager.PlayerTrain.Handles.LocoBrake.Driver < TrainManager.PlayerTrain.LocoBrakeNotchDescriptions.Length) { t = TrainManager.PlayerTrain.LocoBrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.LocoBrake.Driver]; } else { t = Translations.QuickReferences.HandleLocoBrake + TrainManager.PlayerTrain.Handles.LocoBrake.Driver.ToString(Culture); } } } Element.TransitionState = 0.0; break; case "single": if (!TrainManager.PlayerTrain.Handles.SingleHandle) { return; } if (TrainManager.PlayerTrain.Handles.EmergencyBrake.Driver) { sc = MessageColor.Red; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 0) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[0]; } else { t = Translations.QuickReferences.HandleEmergency; } } else if (TrainManager.PlayerTrain.Handles.HoldBrake.Driver) { sc = MessageColor.Green; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1]; } else { t = Translations.QuickReferences.HandleHoldBrake; } } else if (TrainManager.PlayerTrain.Handles.Brake.Driver > 0) { sc = MessageColor.Orange; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.Handles.Brake.Driver + 3 < TrainManager.PlayerTrain.BrakeNotchDescriptions.Length) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[TrainManager.PlayerTrain.Handles.Brake.Driver + 3]; } else { t = Translations.QuickReferences.HandleBrake + TrainManager.PlayerTrain.Handles.Brake.Driver.ToString(Culture); } } else if (TrainManager.PlayerTrain.Handles.Power.Driver > 0) { sc = MessageColor.Blue; if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.Handles.Power.Driver < TrainManager.PlayerTrain.PowerNotchDescriptions.Length) { t = TrainManager.PlayerTrain.PowerNotchDescriptions[TrainManager.PlayerTrain.Handles.Power.Driver]; } else { t = Translations.QuickReferences.HandlePower + TrainManager.PlayerTrain.Handles.Power.Driver.ToString(Culture); } } else { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.PowerNotchDescriptions != null && TrainManager.PlayerTrain.PowerNotchDescriptions.Length > 0) { t = TrainManager.PlayerTrain.PowerNotchDescriptions[0]; } else { t = Translations.QuickReferences.HandlePowerNull; } } Element.TransitionState = 0.0; break; case "doorsleft": case "doorsright": { if ((LeftDoors & TrainManager.TrainDoorState.AllClosed) == 0 | (RightDoors & TrainManager.TrainDoorState.AllClosed) == 0) { Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } TrainManager.TrainDoorState Doors = Command == "doorsleft" ? LeftDoors : RightDoors; if ((Doors & TrainManager.TrainDoorState.Mixed) != 0) { sc = MessageColor.Orange; } else if ((Doors & TrainManager.TrainDoorState.AllClosed) != 0) { sc = MessageColor.Gray; } else if (TrainManager.PlayerTrain.Specs.DoorCloseMode == TrainManager.DoorMode.Manual) { sc = MessageColor.Green; } else { sc = MessageColor.Blue; } t = Command == "doorsleft" ? Translations.QuickReferences.DoorsLeft : Translations.QuickReferences.DoorsRight; } break; case "stopleft": case "stopright": case "stopnone": { int s = TrainManager.PlayerTrain.Station; if (s >= 0 && Game.PlayerStopsAtStation(s) && Interface.CurrentOptions.GameMode != Interface.GameMode.Expert) { bool cond; if (Command == "stopleft") { cond = Game.Stations[s].OpenLeftDoors; } else if (Command == "stopright") { cond = Game.Stations[s].OpenRightDoors; } else { cond = !Game.Stations[s].OpenLeftDoors & !Game.Stations[s].OpenRightDoors; } if (TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Pending & cond) { Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } t = Element.Text; } break; case "stoplefttick": case "stoprighttick": case "stopnonetick": { int s = TrainManager.PlayerTrain.Station; if (s >= 0 && Game.PlayerStopsAtStation(s) && Interface.CurrentOptions.GameMode != Interface.GameMode.Expert) { int c = Game.Stations[s].GetStopIndex(TrainManager.PlayerTrain.Cars.Length); if (c >= 0) { bool cond; if (Command == "stoplefttick") { cond = Game.Stations[s].OpenLeftDoors; } else if (Command == "stoprighttick") { cond = Game.Stations[s].OpenRightDoors; } else { cond = !Game.Stations[s].OpenLeftDoors & !Game.Stations[s].OpenRightDoors; } if (TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Pending & cond) { Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } double d = TrainManager.PlayerTrain.StationDistanceToStopPoint; double r; if (d > 0.0) { r = d / Game.Stations[s].Stops[c].BackwardTolerance; } else { r = d / Game.Stations[s].Stops[c].ForwardTolerance; } if (r < -1.0) { r = -1.0; } if (r > 1.0) { r = 1.0; } y -= r * (double)Element.Value1; } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } t = Element.Text; } break; case "clock": { int hours = (int)Math.Floor(Game.SecondsSinceMidnight); int seconds = hours % 60; hours /= 60; int minutes = hours % 60; hours /= 60; hours %= 24; t = hours.ToString(Culture).PadLeft(2, '0') + ":" + minutes.ToString(Culture).PadLeft(2, '0') + ":" + seconds.ToString(Culture).PadLeft(2, '0'); if (OptionClock) { Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } } break; case "gradient": if (OptionGradient == GradientDisplayMode.Percentage) { if (World.CameraTrackFollower.Pitch != 0) { double pc = World.CameraTrackFollower.Pitch; t = Math.Abs(pc).ToString("0.00", Culture) + "%" + (Math.Abs(pc) == pc ? " ↗" : " ↘"); } else { t = "Level"; } Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else if (OptionGradient == GradientDisplayMode.UnitOfChange) { if (World.CameraTrackFollower.Pitch != 0) { double gr = 1000 / World.CameraTrackFollower.Pitch; t = "1 in " + Math.Abs(gr).ToString("0", Culture) + (Math.Abs(gr) == gr ? " ↗" : " ↘"); } else { t = "Level"; } Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else if (OptionGradient == GradientDisplayMode.Permil) { if (World.CameraTrackFollower.Pitch != 0) { double pm = World.CameraTrackFollower.Pitch; t = Math.Abs(pm).ToString("0.00", Culture) + "‰" + (Math.Abs(pm) == pm ? " ↗" : " ↘"); } else { t = "Level"; } Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { if (World.CameraTrackFollower.Pitch != 0) { double gr = 1000 / World.CameraTrackFollower.Pitch; t = "1 in " + Math.Abs(gr).ToString("0", Culture) + (Math.Abs(gr) == gr ? " ↗" : " ↘"); } else { t = "Level"; } Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } break; case "speed": if (OptionSpeed == SpeedDisplayMode.Kmph) { double kmph = Math.Abs(TrainManager.PlayerTrain.Specs.CurrentAverageSpeed) * 3.6; t = kmph.ToString("0.00", Culture) + " km/h"; Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else if (OptionSpeed == SpeedDisplayMode.Mph) { double mph = Math.Abs(TrainManager.PlayerTrain.Specs.CurrentAverageSpeed) * 2.2369362920544; t = mph.ToString("0.00", Culture) + " mph"; Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { double mph = Math.Abs(TrainManager.PlayerTrain.Specs.CurrentAverageSpeed) * 2.2369362920544; t = mph.ToString("0.00", Culture) + " mph"; Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } break; case "dist_next_station": int i; if (TrainManager.PlayerTrain.Station >= 0 && TrainManager.PlayerTrain.StationState != TrainManager.TrainStopState.Completed) { i = TrainManager.PlayerTrain.LastStation; } else { i = TrainManager.PlayerTrain.LastStation + 1; } if (i > Game.Stations.Length - 1) { i = TrainManager.PlayerTrain.LastStation; } int n = Game.Stations[i].GetStopIndex(TrainManager.PlayerTrain.Cars.Length); double p0 = TrainManager.PlayerTrain.Cars[0].FrontAxle.Follower.TrackPosition - TrainManager.PlayerTrain.Cars[0].FrontAxle.Position + 0.5 * TrainManager.PlayerTrain.Cars[0].Length; double p1; if (Game.Stations[i].Stops.Length > 0) { p1 = Game.Stations[i].Stops[n].TrackPosition; } else { p1 = Game.Stations[i].DefaultTrackPosition; } double m = p1 - p0; if (OptionDistanceToNextStation == DistanceToNextStationDisplayMode.Km) { if (Game.PlayerStopsAtStation(i)) { t = "Stop: "; if (Math.Abs(m) <= 10.0) { t += m.ToString("0.00", Culture) + " m"; } else { m /= 1000.0; t += m.ToString("0.000", Culture) + " km"; } } else { m /= 1000.0; t = "Pass: "******"0.000", Culture) + " km"; } Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else if (OptionDistanceToNextStation == DistanceToNextStationDisplayMode.Mile) { m /= 1609.34; if (Game.PlayerStopsAtStation(i)) { t = "Stop: "; } else { t = "Pass: "******"0.0000", Culture) + " miles"; Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { m /= 1609.34; if (Game.PlayerStopsAtStation(i)) { t = "Stop: "; } else { t = "Pass: "******"0.0000", Culture) + " miles"; Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } break; case "fps": int fps = (int)Math.Round(Game.InfoFrameRate); t = fps.ToString(Culture) + " fps"; if (OptionFrameRates) { Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } break; case "ai": t = "A.I."; if (TrainManager.PlayerTrain.AI != null) { Element.TransitionState -= speed * TimeElapsed; if (Element.TransitionState < 0.0) { Element.TransitionState = 0.0; } } else { Element.TransitionState += speed * TimeElapsed; if (Element.TransitionState > 1.0) { Element.TransitionState = 1.0; } } break; case "score": if (Interface.CurrentOptions.GameMode == Interface.GameMode.Arcade) { t = Game.CurrentScore.CurrentValue.ToString(Culture) + " / " + Game.CurrentScore.Maximum.ToString(Culture); if (Game.CurrentScore.CurrentValue < 0) { sc = MessageColor.Red; } else if (Game.CurrentScore.CurrentValue > 0) { sc = MessageColor.Green; } else { sc = MessageColor.Gray; } Element.TransitionState = 0.0; } else { Element.TransitionState = 1.0; t = ""; } break; default: t = Element.Text; break; } // transitions float alpha = 1.0f; if ((Element.Transition & HUD.Transition.Move) != 0) { double s = Element.TransitionState; x += Element.TransitionVector.X * s * s; y += Element.TransitionVector.Y * s * s; } if ((Element.Transition & HUD.Transition.Fade) != 0) { alpha = (float)(1.0 - Element.TransitionState); } else if (Element.Transition == HUD.Transition.None) { alpha = (float)(1.0 - Element.TransitionState); } // render if (alpha != 0.0f) { // background if (Element.Subject == "reverser") { w = Math.Max(w, TrainManager.PlayerTrain.MaxReverserWidth); //X-Pos doesn't need to be changed } if (Element.Subject == "power") { w = Math.Max(w, TrainManager.PlayerTrain.MaxPowerNotchWidth); if (TrainManager.PlayerTrain.MaxReverserWidth > 48) { x += (TrainManager.PlayerTrain.MaxReverserWidth - 48); } } if (Element.Subject == "brake") { w = Math.Max(w, TrainManager.PlayerTrain.MaxBrakeNotchWidth); if (TrainManager.PlayerTrain.MaxReverserWidth > 48) { x += (TrainManager.PlayerTrain.MaxReverserWidth - 48); } if (TrainManager.PlayerTrain.MaxPowerNotchWidth > 48) { x += (TrainManager.PlayerTrain.MaxPowerNotchWidth - 48); } } if (Element.Subject == "single") { w = Math.Max(Math.Max(w, TrainManager.PlayerTrain.MaxPowerNotchWidth), TrainManager.PlayerTrain.MaxBrakeNotchWidth); if (TrainManager.PlayerTrain.MaxReverserWidth > 48) { x += (TrainManager.PlayerTrain.MaxReverserWidth - 48); } } if (Element.CenterMiddle.BackgroundTexture != null) { if (Textures.LoadTexture(Element.CenterMiddle.BackgroundTexture, OpenGlTextureWrapMode.ClampClamp)) { float r, g, b, a; CreateBackColor(Element.BackgroundColor, sc, out r, out g, out b, out a); GL.Color4(r, g, b, a * alpha); RenderOverlayTexture(Element.CenterMiddle.BackgroundTexture, x, y, x + w, y + h); } } { // text System.Drawing.Size size = MeasureString(Element.Font, t); float u = size.Width; float v = size.Height; double p = Math.Round(Element.TextAlignment.X < 0 ? x : Element.TextAlignment.X == 0 ? x + 0.5 * (w - u) : x + w - u); double q = Math.Round(Element.TextAlignment.Y < 0 ? y : Element.TextAlignment.Y == 0 ? y + 0.5 * (h - v) : y + h - v); p += Element.TextPosition.X; q += Element.TextPosition.Y; float r, g, b, a; CreateTextColor(Element.TextColor, sc, out r, out g, out b, out a); DrawString(Element.Font, t, new System.Drawing.Point((int)p, (int)q), TextAlignment.TopLeft, new Color128(r, g, b, a * alpha), Element.TextShadow); } // overlay if (Element.CenterMiddle.OverlayTexture != null) { if (Textures.LoadTexture(Element.CenterMiddle.OverlayTexture, OpenGlTextureWrapMode.ClampClamp)) { float r, g, b, a; CreateBackColor(Element.OverlayColor, sc, out r, out g, out b, out a); GL.Color4(r, g, b, a * alpha); RenderOverlayTexture(Element.CenterMiddle.OverlayTexture, x, y, x + w, y + h); } } } }
public int TopItem; // the top displayed menu item /******************** * MENU C'TOR *********************/ public SingleMenu(MenuType menuType, int data = 0) { int i, menuItem; int jump = 0; Size size; Align = TextAlignment.TopMiddle; Height = Width = 0; Selection = 0; // defaults to first menu item switch (menuType) { case MenuType.Top: // top level menu for (i = 0; i < Game.Stations.Length; i++) { if (Game.PlayerStopsAtStation(i) & Game.Stations[i].Stops.Length > 0) { jump = 1; break; } } Items = new MenuEntry[4 + jump]; Items[0] = new MenuCommand(Translations.GetInterfaceString("menu_resume"), MenuTag.BackToSim, 0); if (jump > 0) { Items[1] = new MenuCommand(Translations.GetInterfaceString("menu_jump"), MenuTag.MenuJumpToStation, 0); } if (!Interface.CurrentOptions.KioskMode) { //Don't allow quitting or customisation of the controls in kiosk mode Items[1 + jump] = new MenuCommand(Translations.GetInterfaceString("menu_exit"), MenuTag.MenuExitToMainMenu, 0); Items[2 + jump] = new MenuCommand(Translations.GetInterfaceString("menu_customize_controls"), MenuTag.MenuControls, 0); Items[3 + jump] = new MenuCommand(Translations.GetInterfaceString("menu_quit"), MenuTag.MenuQuit, 0); } else { Array.Resize(ref Items, Items.Length - 3); } break; case MenuType.JumpToStation: // list of stations to jump to // count the number of available stations menuItem = 0; for (i = 0; i < Game.Stations.Length; i++) { if (Game.PlayerStopsAtStation(i) & Game.Stations[i].Stops.Length > 0) { menuItem++; } } // list available stations, selecting the next station as predefined choice jump = 0; // no jump found yet Items = new MenuEntry[menuItem + 1]; Items[0] = new MenuCommand(Translations.GetInterfaceString("menu_back"), MenuTag.MenuBack, 0); menuItem = 1; for (i = 0; i < Game.Stations.Length; i++) { if (Game.PlayerStopsAtStation(i) & Game.Stations[i].Stops.Length > 0) { Items[menuItem] = new MenuCommand(Game.Stations[i].Name, MenuTag.JumpToStation, i); // if no preferred jump-to-station found yet and this station is // after the last station the user stopped at, select this item if (jump == 0 && i > TrainManager.PlayerTrain.LastStation) { jump = i; Selection = menuItem; } menuItem++; } } Align = TextAlignment.TopLeft; break; case MenuType.ExitToMainMenu: Items = new MenuEntry[3]; Items[0] = new MenuCaption(Translations.GetInterfaceString("menu_exit_question")); Items[1] = new MenuCommand(Translations.GetInterfaceString("menu_exit_no"), MenuTag.MenuBack, 0); Items[2] = new MenuCommand(Translations.GetInterfaceString("menu_exit_yes"), MenuTag.ExitToMainMenu, 0); Selection = 1; break; case MenuType.Quit: // ask for quit confirmation Items = new MenuEntry[3]; Items[0] = new MenuCaption(Translations.GetInterfaceString("menu_quit_question")); Items[1] = new MenuCommand(Translations.GetInterfaceString("menu_quit_no"), MenuTag.MenuBack, 0); Items[2] = new MenuCommand(Translations.GetInterfaceString("menu_quit_yes"), MenuTag.Quit, 0); Selection = 1; break; case MenuType.Controls: //Refresh the joystick list Program.Joysticks.RefreshJoysticks(); Items = new MenuEntry[Interface.CurrentControls.Length + 1]; Items[0] = new MenuCommand(Translations.GetInterfaceString("menu_back"), MenuTag.MenuBack, 0); for (i = 0; i < Interface.CurrentControls.Length; i++) { Items[i + 1] = new MenuCommand(Interface.CurrentControls[i].Command.ToString(), MenuTag.Control, i); } Align = TextAlignment.TopLeft; break; case MenuType.Control: //Refresh the joystick list Program.Joysticks.RefreshJoysticks(); Selection = SelectionNone; Items = new MenuEntry[4]; // get code name and description Interface.Control loadedControl = Interface.CurrentControls[data]; for (int h = 0; h < Translations.CommandInfos.Length; h++) { if (Translations.CommandInfos[h].Command == loadedControl.Command) { Items[0] = new MenuCommand(loadedControl.Command.ToString() + " - " + Translations.CommandInfos[h].Description, MenuTag.None, 0); break; } } // get assignment String str = ""; switch (loadedControl.Method) { case Interface.ControlMethod.Keyboard: string keyName = loadedControl.Key.ToString(); for (int k = 0; k < Translations.TranslatedKeys.Length; k++) { if (Translations.TranslatedKeys[k].Key == loadedControl.Key) { keyName = Translations.TranslatedKeys[k].Description; break; } } if (loadedControl.Modifier != Interface.KeyboardModifier.None) { str = Translations.GetInterfaceString("menu_keyboard") + " [" + loadedControl.Modifier + "-" + keyName + "]"; } else { str = Translations.GetInterfaceString("menu_keyboard") + " [" + keyName + "]"; } break; case Interface.ControlMethod.Joystick: str = Translations.GetInterfaceString("menu_joystick") + " " + loadedControl.Device + " [" + loadedControl.Component + " " + loadedControl.Element + "]"; switch (loadedControl.Component) { case Interface.JoystickComponent.FullAxis: case Interface.JoystickComponent.Axis: str += " " + (loadedControl.Direction == 1 ? Translations.GetInterfaceString("menu_joystickdirection_positive") : Translations.GetInterfaceString("menu_joystickdirection_negative")); break; // case Interface.JoystickComponent.Button: // NOTHING TO DO FOR THIS CASE! // str = str; // break; case Interface.JoystickComponent.Hat: str += " " + (OpenTK.Input.HatPosition)loadedControl.Direction; break; case Interface.JoystickComponent.Invalid: str = Translations.GetInterfaceString("menu_joystick_notavailable"); break; } break; case Interface.ControlMethod.RailDriver: str = "RailDriver [" + loadedControl.Component + " " + loadedControl.Element + "]"; switch (loadedControl.Component) { case Interface.JoystickComponent.FullAxis: case Interface.JoystickComponent.Axis: str += " " + (loadedControl.Direction == 1 ? Translations.GetInterfaceString("menu_joystickdirection_positive") : Translations.GetInterfaceString("menu_joystickdirection_negative")); break; case Interface.JoystickComponent.Invalid: str = Translations.GetInterfaceString("menu_joystick_notavailable"); break; } break; case Interface.ControlMethod.Invalid: str = Translations.GetInterfaceString("menu_joystick_notavailable"); break; } Items[1] = new MenuCommand(Translations.GetInterfaceString("menu_assignment_current") + " " + str, MenuTag.None, 0); Items[2] = new MenuCommand(" ", MenuTag.None, 0); Items[3] = new MenuCommand(Translations.GetInterfaceString("menu_assign"), MenuTag.None, 0); break; } // compute menu extent for (i = 0; i < Items.Length; i++) { if (Items[i] == null) { continue; } size = Renderer.MeasureString(Game.Menu.MenuFont, Items[i].Text); if (size.Width > Width) { Width = size.Width; } if (!(Items[i] is MenuCaption) && size.Width > ItemWidth) { ItemWidth = size.Width; } } Height = Items.Length * Game.Menu.LineHeight; TopItem = 0; }
// create route map internal static Bitmap CreateRouteMap(int Width, int Height) { // find first and last used element based on stations int n = TrackManager.CurrentTrack.Elements.Length; int n0 = n - 1; int n1 = 0; for (int i = 0; i < TrackManager.CurrentTrack.Elements.Length; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { if (i < n0) { n0 = i; } if (i > n1) { n1 = i; } } } } n0 -= 4; n1 += 8; if (n0 < 0) { n0 = 0; } if (n1 >= TrackManager.CurrentTrack.Elements.Length) { n1 = TrackManager.CurrentTrack.Elements.Length - 1; } if (n1 <= n0) { n1 = n0 + 1; } // find dimensions double x0 = double.PositiveInfinity, z0 = double.PositiveInfinity; double x1 = double.NegativeInfinity, z1 = double.NegativeInfinity; for (int i = n0; i <= n1; i++) { double x = TrackManager.CurrentTrack.Elements[i].WorldPosition.X; double z = TrackManager.CurrentTrack.Elements[i].WorldPosition.Z; if (x < x0) { x0 = x; } if (x > x1) { x1 = x; } if (z < z0) { z0 = z; } if (z > z1) { z1 = z; } } if (x0 >= x1 - 1.0) { x0 = x1 - 1.0; } if (z0 >= z1 - 1.0) { z0 = z1 - 1.0; } double wrh = (double)Width / (double)Height; if ((x1 - x0) / (z1 - z0) <= wrh) { double dx = 0.5 * (z1 - z0) * wrh; double px = 0.5 * (x0 + x1); x0 = px - dx; x1 = px + dx; } else { double dz = 0.5 * (x1 - x0) / wrh; double pz = 0.5 * (z0 + z1); z0 = pz - dz; z1 = pz + dz; } double xd = 1.0 / (x1 - x0); double zd = 1.0 / (z1 - z0); double ox = 8.0, oy = 8.0; double w = (double)(Width - 16); double h = (double)(Height - 16); // create bitmap Bitmap b = new Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(b); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; g.Clear(Color.White); // draw route path { int start = 0; bool atc = false; PointF[] p = new PointF[n]; for (int i = 0; i < n; i++) { double x = TrackManager.CurrentTrack.Elements[i].WorldPosition.X; double z = TrackManager.CurrentTrack.Elements[i].WorldPosition.Z; x = ox + w * (x - x0) * xd; z = oy + h + h * zd * (z0 - z); p[i] = new PointF((float)x, (float)z); // ats/atc for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j]; if (Game.Stations[e.StationIndex].SafetySystem == Game.SafetySystem.Atc) { if (!atc) { atc = true; if (i - start - 1 > 0) { g.DrawCurve(Pens.Black, p, start, i - start - 1); } start = i; } } else { if (atc) { atc = false; if (i - start - 1 > 0) { g.DrawCurve(Pens.DarkRed, p, start, i - start - 1); } start = i; } } } } } DrawSegmentedCurve(g, atc ? Pens.DarkRed : Pens.Black, p, start, n - start - 1); } // draw station circles for (int i = 0; i < n; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j]; if (Game.Stations[e.StationIndex].Name != string.Empty) { double x = TrackManager.CurrentTrack.Elements[i].WorldPosition.X; double y = TrackManager.CurrentTrack.Elements[i].WorldPosition.Z; x = ox + w * (x - x0) * xd; y = oy + h + h * zd * (z0 - y); // station circle RectangleF r = new RectangleF((float)x - 4.0f, (float)y - 4.0f, 8.0f, 8.0f); bool q = Game.PlayerStopsAtStation(e.StationIndex); g.FillEllipse(q ? Brushes.SkyBlue : Brushes.LightGray, r); g.DrawEllipse(q ? Pens.Black : Pens.Gray, r); } } } } // draw station names { double wh = w * h; Font f = new Font(FontFamily.GenericSansSerif, wh < 65536.0 ? 9.0f : 10.0f, GraphicsUnit.Pixel); for (int i = 0; i < n; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j]; if (Game.Stations[e.StationIndex].Name != string.Empty) { double x = TrackManager.CurrentTrack.Elements[i].WorldPosition.X; double y = TrackManager.CurrentTrack.Elements[i].WorldPosition.Z; x = ox + w * (x - x0) * xd; y = oy + h + h * zd * (z0 - y); RectangleF r = new RectangleF((float)x - 4.0f, (float)y - 4.0f, 8.0f, 8.0f); bool stop = Game.PlayerStopsAtStation(e.StationIndex); string t = Game.Stations[e.StationIndex].Name; SizeF m = g.MeasureString(t, f, Width, StringFormat.GenericDefault); double sx = TrackManager.CurrentTrack.Elements[i].WorldSide.X; double sz = TrackManager.CurrentTrack.Elements[i].WorldSide.Z; double xt, yt; if (Math.Sign(sx) == Math.Sign(sz)) { // descending bool o = (x - ox) * (h - y) <= (w - x) * (y - oy); if (o) { // up-right xt = x + 6.0; yt = y - 6.0 - m.Height; } else { // down-left xt = x - 6.0 - m.Width; yt = y + 6.0; } } else { // ascending bool o = (h - y) * (w - x) <= (x - ox) * (y - oy); if (o) { // up-left xt = x - 6.0 - m.Width; yt = y - 6.0 - m.Height; } else { // down-right xt = x + 6.0; yt = y + 6.0; } } if (xt < ox) { xt = ox; } else if (xt + m.Width > w) { xt = w - m.Width; } if (yt < oy) { yt = oy; } else if (yt + m.Height > h) { yt = h - m.Height; } r = new RectangleF((float)xt, (float)yt, m.Width, m.Height); g.FillRectangle(stop ? Brushes.White : Brushes.LightGray, r.Left - 1.0f, r.Top - 1.0f, r.Width + 2.0f, r.Height + 2.0f); g.DrawRectangle(stop ? Pens.Black : Pens.Gray, r.Left - 1.0f, r.Top - 1.0f, r.Width + 2.0f, r.Height + 2.0f); g.DrawString(t, f, stop ? Brushes.Black : Brushes.Gray, (float)xt, (float)yt); } } } } } // finalize return(b); }
// create route gradient profile internal static Bitmap CreateRouteGradientProfile(int Width, int Height) { // find first and last used element based on stations int n = TrackManager.CurrentTrack.Elements.Length; int n0 = n - 1; int n1 = 0; for (int i = 0; i < TrackManager.CurrentTrack.Elements.Length; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { if (i < n0) { n0 = i; } if (i > n1) { n1 = i; } } } } n0 -= 4; n1 += 8; if (n0 < 0) { n0 = 0; } if (n1 >= TrackManager.CurrentTrack.Elements.Length) { n1 = TrackManager.CurrentTrack.Elements.Length - 1; } if (n1 <= n0) { n1 = n0 + 1; } // find dimensions double y0 = double.PositiveInfinity, y1 = double.NegativeInfinity; for (int i = n0; i <= n1; i++) { double y = TrackManager.CurrentTrack.Elements[i].WorldPosition.Y; if (y < y0) { y0 = y; } if (y > y1) { y1 = y; } } if (y0 >= y1 - 1.0) { y0 = y1 - 1.0; } double nd = 1.0 / (double)(n1 - n0); double yd = 1.0 / (double)(y1 - y0); double ox = 8.0, oy = 8.0; double w = (double)(Width - 16); double h = (double)(Height - 32); // create bitmap Bitmap b = new Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); Graphics g = Graphics.FromImage(b); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; g.Clear(Color.White); // draw below sea level { double y = oy + h * (1.0 - 0.5 * (double)(-Game.RouteInitialElevation - y0) * yd); double x0 = ox - w * (double)(n0) * nd; double x1 = ox + w * (double)(n - n0) * nd; g.FillRectangle(Brushes.PaleGoldenrod, (float)x0, (float)y, (float)x1, (float)(oy + h) - (float)y); g.DrawLine(Pens.Gray, (float)x0, (float)y, (float)x1, (float)y); } // draw route path { PointF[] p = new PointF[n + 2]; p[0] = new PointF((float)(ox - w * (double)n0 * nd), (float)(oy + h)); for (int i = 0; i < n; i++) { double x = ox + w * (double)(i - n0) * nd; double y = oy + h * (1.0 - 0.5 * (double)(TrackManager.CurrentTrack.Elements[i].WorldPosition.Y - y0) * yd); p[i + 1] = new PointF((float)x, (float)y); } p[n + 1] = new PointF((float)(ox + w * (double)(n - n0 - 1) * nd), (float)(oy + h)); g.FillPolygon(Brushes.Tan, p); for (int i = 1; i < n; i++) { g.DrawLine(Pens.Black, p[i], p[i + 1]); } g.DrawLine(Pens.Black, 0.0f, (float)(oy + h), (float)Width, (float)(oy + h)); } // draw station names { Font f = new Font(FontFamily.GenericSansSerif, 12.0f, GraphicsUnit.Pixel); StringFormat m = new StringFormat(); for (int i = 0; i < n; i++) { for (int j = 0; j < TrackManager.CurrentTrack.Elements[i].Events.Length; j++) { if (TrackManager.CurrentTrack.Elements[i].Events[j] is TrackManager.StationStartEvent) { TrackManager.StationStartEvent e = (TrackManager.StationStartEvent)TrackManager.CurrentTrack.Elements[i].Events[j]; if (Game.Stations[e.StationIndex].Name != string.Empty) { bool stop = Game.PlayerStopsAtStation(e.StationIndex); if (Interface.IsJapanese(Game.Stations[e.StationIndex].Name)) { m.Alignment = StringAlignment.Near; m.LineAlignment = StringAlignment.Near; double x = ox + w * (double)(i - n0) * nd; double y = oy + h * (1.0 - 0.5 * (double)(TrackManager.CurrentTrack.Elements[i].WorldPosition.Y - y0) * yd); string t = Game.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 ? Brushes.Black : Brushes.LightGray, (float)x - 0.5f * tx, ty); SizeF s = g.MeasureString(t.Substring(k, 1), f, 65536, StringFormat.GenericTypographic); ty += s.Height; } g.DrawLine(stop ? Pens.Gray : Pens.LightGray, 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 + w * (double)(i - n0) * nd; double y = oy + h * (1.0 - 0.5 * (double)(TrackManager.CurrentTrack.Elements[i].WorldPosition.Y - y0) * yd); g.RotateTransform(-90.0f); g.TranslateTransform((float)x, (float)oy, System.Drawing.Drawing2D.MatrixOrder.Append); g.DrawString(Game.Stations[e.StationIndex].Name, f, stop ? Brushes.Black : Brushes.LightGray, new PointF(0.0f, -5.0f), m); g.ResetTransform(); SizeF s = g.MeasureString(Game.Stations[e.StationIndex].Name, f); g.DrawLine(stop ? Pens.Gray : Pens.LightGray, new PointF((float)x, (float)(oy + s.Width + 4)), new PointF((float)x, (float)y)); } } } } } } // draw 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(); m.Alignment = StringAlignment.Far; m.LineAlignment = StringAlignment.Center; System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture; int k = 48 * n / Width; for (int i = 0; i < n; i += k) { double x = ox + w * (double)(i - n0) * nd; double y = (double)(TrackManager.CurrentTrack.Elements[i].WorldPosition.Y - y0) * yd; if (x < w) { string t = ((int)Math.Round(TrackManager.CurrentTrack.Elements[i].StartingTrackPosition)).ToString(Culture); g.DrawString(t + "m", f, Brushes.Black, (float)x, (float)(oy + h + 6.0)); } { y = oy + h * (1.0 - 0.5 * y) + 2.0f; string t = ((int)Math.Round(Game.RouteInitialElevation + TrackManager.CurrentTrack.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, Brushes.Black, 0.0f, 0.0f, m); g.ResetTransform(); g.DrawLine(Pens.Gray, (float)x, (float)(y + s.Width + 12.0), (float)x, (float)(oy + h)); } } } } // finalize return(b); }
/// <summary>This method is called once the route and train data have been preprocessed, in order to physically setup the simulation</summary> private void SetupSimulation() { if (Loading.Cancel) { Close(); } Timetable.CreateTimetable(); //Check if any critical errors have occured during the route or train loading for (int i = 0; i < Interface.MessageCount; i++) { if (Interface.Messages[i].Type == Interface.MessageType.Critical) { MessageBox.Show("A critical error has occured:\n\n" + Interface.Messages[i].Text + "\n\nPlease inspect the error log file for further information.", "Load", MessageBoxButtons.OK, MessageBoxIcon.Hand); Close(); } } Renderer.InitializeLighting(); Game.LogRouteName = System.IO.Path.GetFileName(MainLoop.currentResult.RouteFile); Game.LogTrainName = System.IO.Path.GetFileName(MainLoop.currentResult.TrainFolder); Game.LogDateTime = DateTime.Now; if (Interface.CurrentOptions.LoadInAdvance) { Textures.LoadAllTextures(); } else { Textures.UnloadAllTextures(); } // camera ObjectManager.InitializeVisibility(); TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, 0.0, true, false); TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, -0.1, true, false); TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, 0.1, true, false); World.CameraTrackFollower.TriggerType = TrackManager.EventTriggerType.Camera; // starting time and track position Game.SecondsSinceMidnight = 0.0; Game.StartupTime = 0.0; int PlayerFirstStationIndex = -1; double PlayerFirstStationPosition = 0.0; for (int i = 0; i < Game.Stations.Length; i++) { if (Game.Stations[i].StopMode == Game.StationStopMode.AllStop | Game.Stations[i].StopMode == Game.StationStopMode.PlayerStop & Game.Stations[i].Stops.Length != 0) { PlayerFirstStationIndex = i; int s = Game.GetStopIndex(i, TrainManager.PlayerTrain.Cars.Length); if (s >= 0) { PlayerFirstStationPosition = Game.Stations[i].Stops[s].TrackPosition; double TrainLength = 0.0; for (int c = 0; c < TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars.Length; c++) { TrainLength += TrainManager.Trains[TrainManager.PlayerTrain.TrainIndex].Cars[c].Length; } for (int j = 0; j < Game.BufferTrackPositions.Length; j++) { if (PlayerFirstStationPosition > Game.BufferTrackPositions[j] && PlayerFirstStationPosition - TrainLength < Game.BufferTrackPositions[j]) { /* * HACK: The initial start position for the player train is stuck on a set of buffers * This means we have to make some one the fly adjustments to the first station stop position */ //Set the start position to be the buffer position plus the train length plus 1m PlayerFirstStationPosition = Game.BufferTrackPositions[j] + TrainLength + 1; //Update the station stop location if (s >= 0) { Game.Stations[PlayerFirstStationIndex].Stops[s].TrackPosition = PlayerFirstStationPosition; } else { Game.Stations[PlayerFirstStationIndex].DefaultTrackPosition = PlayerFirstStationPosition; } break; } } } else { PlayerFirstStationPosition = Game.Stations[i].DefaultTrackPosition; } if (Game.Stations[i].ArrivalTime < 0.0) { if (Game.Stations[i].DepartureTime < 0.0) { Game.SecondsSinceMidnight = 0.0; Game.StartupTime = 0.0; } else { Game.SecondsSinceMidnight = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime; Game.StartupTime = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime; } } else { Game.SecondsSinceMidnight = Game.Stations[i].ArrivalTime; Game.StartupTime = Game.Stations[i].ArrivalTime; } break; } } int OtherFirstStationIndex = -1; double OtherFirstStationPosition = 0.0; double OtherFirstStationTime = 0.0; for (int i = 0; i < Game.Stations.Length; i++) { if (Game.Stations[i].StopMode == Game.StationStopMode.AllStop | Game.Stations[i].StopMode == Game.StationStopMode.PlayerPass & Game.Stations[i].Stops.Length != 0) { OtherFirstStationIndex = i; int s = Game.GetStopIndex(i, TrainManager.PlayerTrain.Cars.Length); if (s >= 0) { OtherFirstStationPosition = Game.Stations[i].Stops[s].TrackPosition; } else { OtherFirstStationPosition = Game.Stations[i].DefaultTrackPosition; } if (Game.Stations[i].ArrivalTime < 0.0) { if (Game.Stations[i].DepartureTime < 0.0) { OtherFirstStationTime = 0.0; } else { OtherFirstStationTime = Game.Stations[i].DepartureTime - Game.Stations[i].StopTime; } } else { OtherFirstStationTime = Game.Stations[i].ArrivalTime; } break; } } if (Game.PrecedingTrainTimeDeltas.Length != 0) { OtherFirstStationTime -= Game.PrecedingTrainTimeDeltas[Game.PrecedingTrainTimeDeltas.Length - 1]; if (OtherFirstStationTime < Game.SecondsSinceMidnight) { Game.SecondsSinceMidnight = OtherFirstStationTime; } } // initialize trains for (int i = 0; i < TrainManager.Trains.Length; i++) { TrainManager.InitializeTrain(TrainManager.Trains[i]); int s = i == TrainManager.PlayerTrain.TrainIndex ? PlayerFirstStationIndex : OtherFirstStationIndex; if (s >= 0) { if (Game.Stations[s].OpenLeftDoors) { for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { TrainManager.Trains[i].Cars[j].Specs.AnticipatedLeftDoorsOpened = true; } } if (Game.Stations[s].OpenRightDoors) { for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { TrainManager.Trains[i].Cars[j].Specs.AnticipatedRightDoorsOpened = true; } } } if (Game.Sections.Length != 0) { Game.Sections[0].Enter(TrainManager.Trains[i]); } for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { double length = TrainManager.Trains[i].Cars[0].Length; TrainManager.MoveCar(TrainManager.Trains[i], j, -length, 0.01); TrainManager.MoveCar(TrainManager.Trains[i], j, length, 0.01); } } // score Game.CurrentScore.ArrivalStation = PlayerFirstStationIndex + 1; Game.CurrentScore.DepartureStation = PlayerFirstStationIndex; Game.CurrentScore.Maximum = 0; for (int i = 0; i < Game.Stations.Length; i++) { if (i != PlayerFirstStationIndex & Game.PlayerStopsAtStation(i)) { if (i == 0 || Game.Stations[i - 1].StationType != Game.StationType.ChangeEnds) { Game.CurrentScore.Maximum += Game.ScoreValueStationArrival; } } } if (Game.CurrentScore.Maximum <= 0) { Game.CurrentScore.Maximum = Game.ScoreValueStationArrival; } // signals if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } // move train in position for (int i = 0; i < TrainManager.Trains.Length; i++) { double p; if (i == TrainManager.PlayerTrain.TrainIndex) { p = PlayerFirstStationPosition; } else if (TrainManager.Trains[i].State == TrainManager.TrainState.Bogus) { p = Game.BogusPretrainInstructions[0].TrackPosition; TrainManager.Trains[i].AI = new Game.BogusPretrainAI(TrainManager.Trains[i]); } else { p = OtherFirstStationPosition; } for (int j = 0; j < TrainManager.Trains[i].Cars.Length; j++) { TrainManager.MoveCar(TrainManager.Trains[i], j, p, 0.01); } } // timetable if (Timetable.DefaultTimetableDescription.Length == 0) { Timetable.DefaultTimetableDescription = Game.LogTrainName; } // initialize camera if (World.CameraRestriction == World.CameraRestrictionMode.NotAvailable) { World.CameraMode = World.CameraViewMode.InteriorLookAhead; } //Place the initial camera in the driver car TrainManager.UpdateCamera(TrainManager.PlayerTrain, TrainManager.PlayerTrain.DriverCar); TrackManager.UpdateTrackFollower(ref World.CameraTrackFollower, -1.0, true, false); ObjectManager.UpdateVisibility(World.CameraTrackFollower.TrackPosition + World.CameraCurrentAlignment.Position.Z); World.CameraSavedInterior = new World.CameraAlignment(); World.CameraSavedExterior = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-2.5, 1.5, -15.0), 0.3, -0.2, 0.0, PlayerFirstStationPosition, 1.0); World.CameraSavedTrack = new World.CameraAlignment(new OpenBveApi.Math.Vector3(-3.0, 2.5, 0.0), 0.3, 0.0, 0.0, TrainManager.PlayerTrain.Cars[0].FrontAxle.Follower.TrackPosition - 10.0, 1.0); // signalling sections for (int i = 0; i < TrainManager.Trains.Length; i++) { int s = TrainManager.Trains[i].CurrentSectionIndex; Game.Sections[s].Enter(TrainManager.Trains[i]); } if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } // fast-forward until start time { Game.MinimalisticSimulation = true; const double w = 0.25; double u = Game.StartupTime - Game.SecondsSinceMidnight; if (u > 0) { while (true) { double v = u < w ? u : w; u -= v; Game.SecondsSinceMidnight += v; TrainManager.UpdateTrains(v); if (u <= 0.0) { break; } TotalTimeElapsedForSectionUpdate += v; if (TotalTimeElapsedForSectionUpdate >= 1.0) { if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } TotalTimeElapsedForSectionUpdate = 0.0; } } } Game.MinimalisticSimulation = false; } // animated objects ObjectManager.UpdateAnimatedWorldObjects(0.0, true); TrainManager.UpdateTrainObjects(0.0, true); // timetable if (TrainManager.PlayerTrain.Station >= 0) { Timetable.UpdateCustomTimetable(Game.Stations[TrainManager.PlayerTrain.Station].TimetableDaytimeTexture, Game.Stations[TrainManager.PlayerTrain.Station].TimetableNighttimeTexture); if (Timetable.CustomObjectsUsed != 0 & Timetable.CustomTimetableAvailable && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.AutoGenerated && Interface.CurrentOptions.TimeTableStyle != Interface.TimeTableMode.None) { Timetable.CurrentTimetable = Timetable.TimetableState.Custom; } } // warnings / errors if (Interface.MessageCount != 0) { int filesNotFound = 0; int errors = 0; int warnings = 0; for (int i = 0; i < Interface.MessageCount; i++) { if (Interface.Messages[i].FileNotFound) { filesNotFound++; } else if (Interface.Messages[i].Type == Interface.MessageType.Error) { errors++; } else if (Interface.Messages[i].Type == Interface.MessageType.Warning) { warnings++; } } string NotFound = null; string Messages = null; if (filesNotFound != 0) { NotFound = filesNotFound.ToString() + " file(s) not found"; Game.AddDebugMessage(NotFound, 10.0); } if (errors != 0 & warnings != 0) { Messages = errors.ToString() + " error(s), " + warnings.ToString() + " warning(s)"; Game.AddDebugMessage(Messages, 10.0); } else if (errors != 0) { Messages = errors.ToString() + " error(s)"; Game.AddDebugMessage(Messages, 10.0); } else { Messages = warnings.ToString() + " warning(s)"; Game.AddDebugMessage(Messages, 10.0); } Game.RouteInformation.FilesNotFound = NotFound; Game.RouteInformation.ErrorsAndWarnings = Messages; //Print the plugin error encountered (If any) for 10s //This must be done after the simulation has init, as otherwise the timeout doesn't work if (Loading.PluginError != null) { Game.AddMessage(Loading.PluginError, Game.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0); Game.AddMessage(Interface.GetInterfaceString("errors_plugin_failure2"), Game.MessageDependency.None, Interface.GameMode.Expert, OpenBveApi.Colors.MessageColor.Red, Game.SecondsSinceMidnight + 5.0); } } loadComplete = true; RenderRealTimeElapsed = 0.0; RenderTimeElapsed = 0.0; World.InitializeCameraRestriction(); }