/// <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; } }
/// <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 = Game.GetStopIndex(j, TrainManager.PlayerTrain.Cars.Length); if (p >= 0) { if (Math.Abs(TrainManager.PlayerTrain.Specs.CurrentAverageSpeed) < 0.1) { if (leftopen == Stations[j].OpenLeftDoors & rightopen == Stations[j].OpenRightDoors) { bad = false; } } } } } else { bad = false; } if (bad) { OpenedDoorsCounter += (Math.Abs(TrainManager.PlayerTrain.Specs.CurrentAverageSpeed) + 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.Specs.CurrentAverageSpeed) - 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 < Stations.Length) { if (j >= ArrivalStation & TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Boarding) { if (j == 0 || 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 (Stations[j].ArrivalTime >= 0) { double d = SecondsSinceMidnight - 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 = Game.GetStopIndex(j, TrainManager.PlayerTrain.Cars.Length); if (p >= 0) { double d = TrainManager.PlayerTrain.StationDistanceToStopPoint; double r; if (d >= 0) { double t = 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 = 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 == Interface.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 == Interface.GameMode.Arcade) { if (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 < Stations.Length & j == DepartureStation) { bool q; if (Stations[j].OpenLeftDoors | Stations[j].OpenRightDoors) { q = TrainManager.PlayerTrain.StationState == TrainManager.TrainStopState.Completed; } else { q = TrainManager.PlayerTrain.StationState != TrainManager.TrainStopState.Pending & (TrainManager.PlayerTrain.Specs.CurrentAverageSpeed <-1.5 | TrainManager.PlayerTrain.Specs.CurrentAverageSpeed> 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>Jumps a train to a new station</summary> /// <param name="train">The train</param> /// <param name="stationIndex">The zero-based index of the station</param> internal static void JumpTrain(Train train, int stationIndex) { if (train == PlayerTrain) { for (int i = 0; i < ObjectManager.AnimatedWorldObjects.Length; i++) { var obj = ObjectManager.AnimatedWorldObjects[i] as ObjectManager.TrackFollowingObject; if (obj != null) { //Track followers should be reset if we jump between stations obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.FrontAxlePosition; obj.FrontAxleFollower.TrackPosition = ObjectManager.AnimatedWorldObjects[i].TrackPosition + obj.RearAxlePosition; obj.FrontAxleFollower.UpdateWorldCoordinates(false); obj.RearAxleFollower.UpdateWorldCoordinates(false); } } } train.StationState = TrainStopState.Jumping; int stopIndex = Game.GetStopIndex(stationIndex, train.Cars.Length); if (stopIndex >= 0) { if (train == PlayerTrain) { if (train.Plugin != null) { train.Plugin.BeginJump((OpenBveApi.Runtime.InitializationModes)Game.TrainStart); } } for (int h = 0; h < train.Cars.Length; h++) { train.Cars[h].Specs.CurrentSpeed = 0.0; } double d = Game.Stations[stationIndex].Stops[stopIndex].TrackPosition - train.Cars[0].FrontAxle.Follower.TrackPosition + train.Cars[0].FrontAxle.Position - 0.5 * train.Cars[0].Length; if (train == PlayerTrain) { TrackManager.SuppressSoundEvents = true; } while (d != 0.0) { double x; if (Math.Abs(d) > 1.0) { x = (double)Math.Sign(d); } else { x = d; } for (int h = 0; h < train.Cars.Length; h++) { train.Cars[h].Move(x, 0.0); } if (Math.Abs(d) >= 1.0) { d -= x; } else { break; } } if (train == PlayerTrain) { TrainManager.UnderailTrains(); TrackManager.SuppressSoundEvents = false; } if (train.Handles.EmergencyBrake.Driver) { train.ApplyNotch(0, false, 0, true); } else { train.ApplyNotch(0, false, train.Handles.Brake.MaximumNotch, false); train.ApplyAirBrakeHandle(TrainManager.AirBrakeHandleState.Service); } if (Game.Sections.Length > 0) { Game.UpdateSection(Game.Sections.Length - 1); } if (train == PlayerTrain) { if (Game.CurrentScore.ArrivalStation <= stationIndex) { Game.CurrentScore.ArrivalStation = stationIndex + 1; } } if (train == PlayerTrain) { if (Game.Stations[stationIndex].ArrivalTime >= 0.0) { Game.SecondsSinceMidnight = Game.Stations[stationIndex].ArrivalTime; } else if (Game.Stations[stationIndex].DepartureTime >= 0.0) { Game.SecondsSinceMidnight = Game.Stations[stationIndex].DepartureTime - Game.Stations[stationIndex].StopTime; } } for (int i = 0; i < train.Cars.Length; i++) { train.Cars[i].Doors[0].AnticipatedOpen = Game.Stations[stationIndex].OpenLeftDoors; train.Cars[i].Doors[1].AnticipatedOpen = Game.Stations[stationIndex].OpenRightDoors; } if (train == PlayerTrain) { Game.CurrentScore.DepartureStation = stationIndex; Game.CurrentInterface = Game.InterfaceType.Normal; //Game.Messages = new Game.Message[] { }; } ObjectManager.UpdateAnimatedWorldObjects(0.0, true); TrainManager.UpdateTrainObjects(0.0, true); if (train == PlayerTrain) { if (train.Plugin != null) { train.Plugin.EndJump(); } } train.StationState = TrainStopState.Pending; } }
/// <summary>Is called once a frame to update the station state for the given train</summary> /// <param name="Train">The train</param> /// <param name="TimeElapsed">The frame time elapsed</param> private static void UpdateTrainStation(Train Train, double TimeElapsed) { if (Train.Station >= 0) { int i = Train.Station; int n = Game.GetStopIndex(Train.Station, Train.Cars.Length); double tf, tb; if (n >= 0) { double p0 = Train.Cars[0].FrontAxle.Follower.TrackPosition - Train.Cars[0].FrontAxle.Position + 0.5 * Train.Cars[0].Length; double p1 = Game.Stations[i].Stops[n].TrackPosition; tf = Game.Stations[i].Stops[n].ForwardTolerance; tb = Game.Stations[i].Stops[n].BackwardTolerance; Train.StationDistanceToStopPoint = p1 - p0; } else { Train.StationDistanceToStopPoint = 0.0; tf = 5.0; tb = 5.0; } if (Train.StationState == TrainStopState.Pending) { Train.StationDepartureSoundPlayed = false; if (Game.StopsAtStation(i, Train)) { Train.StationDepartureSoundPlayed = false; //Check whether all doors are controlled by the driver if (Train.Specs.DoorOpenMode != DoorMode.Manual) { //Check that we are not moving if (Math.Abs(Train.Specs.CurrentAverageSpeed) < 0.1 / 3.6 & Math.Abs(Train.Specs.CurrentAverageAcceleration) < 0.1 / 3.6) { //Check the interlock state for the doors switch (Train.Specs.DoorInterlockState) { case DoorInterlockStates.Unlocked: if (Game.Stations[i].OpenLeftDoors || Game.Stations[i].OpenRightDoors) { AttemptToOpenDoors(Train, i, tb, tf); } break; case DoorInterlockStates.Left: if (Game.Stations[i].OpenLeftDoors && !Game.Stations[i].OpenRightDoors) { AttemptToOpenDoors(Train, i, tb, tf); } break; case DoorInterlockStates.Right: if (!Game.Stations[i].OpenLeftDoors && Game.Stations[i].OpenRightDoors) { AttemptToOpenDoors(Train, i, tb, tf); } break; case DoorInterlockStates.Locked: //All doors are currently locked, do nothing break; } } } // detect arrival if (Train.Specs.CurrentAverageSpeed > -0.277777777777778 & Train.Specs.CurrentAverageSpeed < 0.277777777777778) { bool left, right; if (Game.Stations[i].OpenLeftDoors) { left = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Specs.AnticipatedLeftDoorsOpened) { left = true; break; } } } else { left = true; } if (Game.Stations[i].OpenRightDoors) { right = false; for (int j = 0; j < Train.Cars.Length; j++) { if (Train.Cars[j].Specs.AnticipatedRightDoorsOpened) { right = true; break; } } } else { right = true; } if (left & right) { // arrival Train.StationState = TrainStopState.Boarding; Train.StationAdjust = false; Train.Specs.DoorClosureAttempted = false; Sounds.StopSound(Train.Cars[Train.DriverCar].Sounds.Halt.Source); Sounds.SoundBuffer buffer = Game.Stations[i].ArrivalSoundBuffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Game.Stations[i].SoundOrigin; Sounds.PlaySound(buffer, 1.0, 1.0, pos, false); } Train.StationArrivalTime = Game.SecondsSinceMidnight; Train.StationDepartureTime = Game.Stations[i].DepartureTime - Train.TimetableDelta; if (Train.StationDepartureTime - Game.SecondsSinceMidnight < Game.Stations[i].StopTime) { Train.StationDepartureTime = Game.SecondsSinceMidnight + Game.Stations[i].StopTime; } Train.Passengers.PassengerRatio = Game.Stations[i].PassengerRatio; UpdateTrainMassFromPassengerRatio(Train); if (Train == PlayerTrain) { double early = 0.0; if (Game.Stations[i].ArrivalTime >= 0.0) { early = (Game.Stations[i].ArrivalTime - Train.TimetableDelta) - Train.StationArrivalTime; } string s; if (early < -1.0) { s = Interface.GetInterfaceString("message_station_arrival_late"); } else if (early > 1.0) { s = Interface.GetInterfaceString("message_station_arrival_early"); } else { s = Interface.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 += Interface.GetInterfaceString("message_delimiter") + Interface.GetInterfaceString("message_station_overrun"); } else if (Train.StationDistanceToStopPoint > 0.1) { s += Interface.GetInterfaceString("message_delimiter") + Interface.GetInterfaceString("message_station_underrun"); } double d = Math.Abs(Train.StationDistanceToStopPoint); string c = d.ToString("0.0", Culture); if (Game.Stations[i].StationType == Game.StationType.Terminal) { s += Interface.GetInterfaceString("message_delimiter") + Interface.GetInterfaceString("message_station_terminal"); } s = s.Replace("[name]", Game.Stations[i].Name); s = s.Replace("[time]", b); s = s.Replace("[difference]", c); Game.AddMessage(s, MessageManager.MessageDependency.StationArrival, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 10.0, null); if (Game.Stations[i].StationType == Game.StationType.Normal) { s = Interface.GetInterfaceString("message_station_deadline"); Game.AddMessage(s, MessageManager.MessageDependency.StationDeparture, Interface.GameMode.Normal, MessageColor.White, double.PositiveInfinity, null); } Timetable.UpdateCustomTimetable(Game.Stations[i].TimetableDaytimeTexture, Game.Stations[i].TimetableNighttimeTexture); } // schedule door locks (passengers stuck between the doors) for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { Train.Cars[j].Specs.Doors[k].DoorLockDuration = 0.0; if (Game.Stations[i].OpenLeftDoors & Train.Cars[j].Specs.Doors[k].Direction == -1 | Game.Stations[i].OpenRightDoors & Train.Cars[j].Specs.Doors[k].Direction == 1) { double p = 0.005 * Game.Stations[i].PassengerRatio * Game.Stations[i].PassengerRatio * Game.Stations[i].PassengerRatio * Game.Stations[i].PassengerRatio; if (Program.RandomNumberGenerator.NextDouble() < p) { /* * -- door lock at state -- * minimum: 0.2 (nearly closed) * maximum: 0.8 (nearly opened) * */ Train.Cars[j].Specs.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].Specs.Doors[k].DoorLockDuration = (50.0 - 10.0 * p) / (17.0 - 16.0 * p); } } } } } else if (Train.Specs.CurrentAverageSpeed > -0.277777777777778 & Train.Specs.CurrentAverageSpeed < 0.277777777777778) { // correct stop position if (!Train.StationAdjust & (Train.StationDistanceToStopPoint > tb | Train.StationDistanceToStopPoint < -tf)) { Sounds.SoundBuffer buffer = Train.Cars[Train.DriverCar].Sounds.Adjust.Buffer; if (buffer != null) { OpenBveApi.Math.Vector3 pos = Train.Cars[Train.DriverCar].Sounds.Adjust.Position; Sounds.PlaySound(buffer, 1.0, 1.0, pos, Train, Train.DriverCar, false); } if (Train == TrainManager.PlayerTrain) { Game.AddMessage(Interface.GetInterfaceString("message_station_correct"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.Orange, Game.SecondsSinceMidnight + 5.0, null); } Train.StationAdjust = true; } } else { Train.StationAdjust = false; } } } } else if (Train.StationState == TrainStopState.Boarding) { //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.DoorOpenMode != DoorMode.Manual & Game.Stations[i].StationType == Game.StationType.Normal) { //Check the interlock state for the doors switch (Train.Specs.DoorInterlockState) { case DoorInterlockStates.Unlocked: AttemptToCloseDoors(Train); break; case DoorInterlockStates.Left: if (Game.Stations[i].OpenLeftDoors) { AttemptToCloseDoors(Train); } break; case DoorInterlockStates.Right: if (Game.Stations[i].OpenRightDoors) { AttemptToCloseDoors(Train); } break; case DoorInterlockStates.Locked: //All doors are currently locked, do nothing break; } } // detect departure bool left, right; if (!Game.Stations[i].OpenLeftDoors & !Game.Stations[i].OpenRightDoors) { left = true; right = true; } else { if (Game.Stations[i].OpenLeftDoors) { left = false; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].State != 0.0) { left = true; break; } } if (left) { break; } } } else { left = false; } if (Game.Stations[i].OpenRightDoors) { right = false; for (int j = 0; j < Train.Cars.Length; j++) { for (int k = 0; k < Train.Cars[j].Specs.Doors.Length; k++) { if (Train.Cars[j].Specs.Doors[k].State != 0.0) { right = true; break; } } if (right) { break; } } } else { right = false; } } if (left | right) { // departure message if (Game.SecondsSinceMidnight > Train.StationDepartureTime && (Game.Stations[i].StationType != Game.StationType.Terminal || Train != PlayerTrain)) { Train.StationState = TrainStopState.Completed; if (Train == PlayerTrain & Game.Stations[i].StationType == Game.StationType.Normal) { if (!Game.Stations[i].OpenLeftDoors & !Game.Stations[i].OpenRightDoors | Train.Specs.DoorCloseMode != DoorMode.Manual) { Game.AddMessage(Interface.GetInterfaceString("message_station_depart"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 5.0, null); } else { Game.AddMessage(Interface.GetInterfaceString("message_station_depart_closedoors"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 5.0, null); } } else if (Game.Stations[i].StationType == Game.StationType.ChangeEnds) { //Game.AddMessage("CHANGE ENDS", MessageManager.MessageDependency.None, Interface.GameMode.Expert, MessageColor.Magenta, Game.SecondsSinceMidnight + 5.0); JumpTrain(Train, i + 1); } } if (Interface.CurrentOptions.LoadingSway) { // passengers boarding for (int j = 0; j < Train.Cars.Length; j++) { double r = 2.0 * Game.Stations[i].PassengerRatio * TimeElapsed; if (r >= Program.RandomNumberGenerator.NextDouble()) { int d = (int)Math.Floor(Program.RandomNumberGenerator.NextDouble() * (double)Train.Cars[j].Specs.Doors.Length); if (Train.Cars[j].Specs.Doors[d].State == 1.0) { Train.Cars[j].Specs.CurrentRollShakeDirection += (double)Train.Cars[j].Specs.Doors[d].Direction; } } } } } else { Train.StationState = TrainStopState.Completed; if (Train == PlayerTrain & Game.Stations[i].StationType == Game.StationType.Normal) { Game.AddMessage(Interface.GetInterfaceString("message_station_depart"), MessageManager.MessageDependency.None, Interface.GameMode.Normal, MessageColor.White, Game.SecondsSinceMidnight + 5.0, null); } } // departure sound if (!Train.StationDepartureSoundPlayed) { Sounds.SoundBuffer buffer = Game.Stations[i].DepartureSoundBuffer; if (buffer != null) { double dur = Sounds.GetDuration(buffer); if (Game.SecondsSinceMidnight >= Train.StationDepartureTime - dur) { Sounds.PlaySound(buffer, 1.0, 1.0, Game.Stations[i].SoundOrigin, false); Train.StationDepartureSoundPlayed = true; } } } } } else { Train.StationState = TrainStopState.Pending; } // automatically close doors if (Train.Specs.DoorCloseMode != DoorMode.Manual & Train.Specs.DoorInterlockState != DoorInterlockStates.Locked & !Train.Specs.DoorClosureAttempted) { if (Train.Station == -1 | Train.StationState == TrainStopState.Completed) { if ((GetDoorsState(Train, true, true) & TrainDoorState.AllClosed) == 0) { CloseTrainDoors(Train, true, true); Train.Specs.DoorClosureAttempted = true; } } } }
/// <summary>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(Interface.HudElement 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, Textures.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 = Interface.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 = Interface.QuickReferences.HandleForward; } } else { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.ReverserDescriptions != null && TrainManager.PlayerTrain.ReverserDescriptions.Length > 1) { t = TrainManager.PlayerTrain.ReverserDescriptions[1]; } else { t = Interface.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 = Interface.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 = Interface.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.Cars[TrainManager.PlayerTrain.DriverCar].Specs.BrakeType == TrainManager.CarBrakeType.AutomaticAirBrake) { 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 = Interface.QuickReferences.HandleEmergency; } } else if (TrainManager.PlayerTrain.Handles.AirBrake.Handle.Driver == TrainManager.AirBrakeHandleState.Release) { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 1) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[1]; } else { t = Interface.QuickReferences.HandleRelease; } } else if (TrainManager.PlayerTrain.Handles.AirBrake.Handle.Driver == TrainManager.AirBrakeHandleState.Lap) { sc = MessageColor.Blue; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 2) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[2]; } else { t = Interface.QuickReferences.HandleLap; } } else { sc = MessageColor.Orange; if (TrainManager.PlayerTrain.BrakeNotchDescriptions != null && TrainManager.PlayerTrain.BrakeNotchDescriptions.Length > 3) { t = TrainManager.PlayerTrain.BrakeNotchDescriptions[3]; } else { t = Interface.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 = Interface.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 = Interface.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 = Interface.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 = Interface.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.Driver == 0) { sc = MessageColor.Gray; if (TrainManager.PlayerTrain.LocoBrakeNotchDescriptions != null && TrainManager.PlayerTrain.LocoBrakeNotchDescriptions.Length > 1) { t = TrainManager.PlayerTrain.LocoBrakeNotchDescriptions[1]; } else { t = Interface.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 = Interface.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 = Interface.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 = Interface.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 = Interface.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 = Interface.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 = Interface.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" ? Interface.QuickReferences.DoorsLeft : Interface.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.GetStopIndex(s, 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 (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 "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 & Interface.HudTransition.Move) != 0) { double s = Element.TransitionState; x += Element.TransitionVector.X * s * s; y += Element.TransitionVector.Y * s * s; } if ((Element.Transition & Interface.HudTransition.Fade) != 0) { alpha = (float)(1.0 - Element.TransitionState); } else if (Element.Transition == Interface.HudTransition.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, Textures.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, Textures.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); } } } }
/// <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(); }
/// <summary>Called every frame to update the plugin.</summary> internal void UpdatePlugin() { if (Train.Cars == null || Train.Cars.Length == 0) { return; } /* * Prepare the vehicle state. * */ double location = this.Train.Cars[0].FrontAxle.Follower.TrackPosition - this.Train.Cars[0].FrontAxle.Position + 0.5 * this.Train.Cars[0].Length; //Curve Radius, Cant and Pitch Added double CurrentRadius = this.Train.Cars[0].FrontAxle.Follower.CurveRadius; double CurrentCant = this.Train.Cars[0].FrontAxle.Follower.CurveCant; double CurrentPitch = this.Train.Cars[0].FrontAxle.Follower.Pitch; //If the list of stations has not been loaded, do so if (!StationsLoaded) { currentRouteStations = new List <Station>(); int s = 0; foreach (Game.Station selectedStation in Game.Stations) { double stopPosition = -1; int stopIdx = Game.GetStopIndex(s, Train.Cars.Length); if (selectedStation.Stops.Length != 0) { stopPosition = selectedStation.Stops[stopIdx].TrackPosition; } Station i = new Station(selectedStation, stopPosition); currentRouteStations.Add(i); s++; } StationsLoaded = true; } //End of additions double speed = this.Train.Cars[this.Train.DriverCar].Specs.CurrentPerceivedSpeed; double bcPressure = this.Train.Cars[this.Train.DriverCar].Specs.AirBrake.BrakeCylinderCurrentPressure; double mrPressure = this.Train.Cars[this.Train.DriverCar].Specs.AirBrake.MainReservoirCurrentPressure; double erPressure = this.Train.Cars[this.Train.DriverCar].Specs.AirBrake.EqualizingReservoirCurrentPressure; double bpPressure = this.Train.Cars[this.Train.DriverCar].Specs.AirBrake.BrakePipeCurrentPressure; double sapPressure = this.Train.Cars[this.Train.DriverCar].Specs.AirBrake.StraightAirPipeCurrentPressure; VehicleState vehicle = new VehicleState(location, new Speed(speed), bcPressure, mrPressure, erPressure, bpPressure, sapPressure, CurrentRadius, CurrentCant, CurrentPitch); /* * Prepare the preceding vehicle state. * */ double bestLocation = double.MaxValue; double bestSpeed = 0.0; PrecedingVehicleState precedingVehicle; try { for (int i = 0; i < TrainManager.Trains.Length; i++) { if (TrainManager.Trains[i] != this.Train & TrainManager.Trains[i].State == TrainManager.TrainState.Available & Train.Cars.Length > 0) { int c = TrainManager.Trains[i].Cars.Length - 1; double z = TrainManager.Trains[i].Cars[c].RearAxle.Follower.TrackPosition - TrainManager.Trains[i].Cars[c].RearAxle.Position - 0.5 * TrainManager.Trains[i].Cars[c].Length; if (z >= location & z < bestLocation) { bestLocation = z; bestSpeed = TrainManager.Trains[i].Specs.CurrentAverageSpeed; } } } precedingVehicle = bestLocation != double.MaxValue ? new PrecedingVehicleState(bestLocation, bestLocation - location, new Speed(bestSpeed)) : null; } catch { precedingVehicle = null; } /* * Get the driver handles. * */ Handles handles = GetHandles(); /* * Update the plugin. * */ double totalTime = Game.SecondsSinceMidnight; double elapsedTime = Game.SecondsSinceMidnight - LastTime; /* * Set the current camera view mode * Could probably do away with the CurrentCameraViewMode and use a direct cast?? * */ CurrentCameraViewMode = (CameraViewMode)World.CameraMode; ElapseData data = new ElapseData(vehicle, precedingVehicle, handles, (DoorInterlockStates)this.Train.Specs.DoorInterlockState, new Time(totalTime), new Time(elapsedTime), currentRouteStations, CurrentCameraViewMode, Interface.CurrentLanguageCode, this.Train.Destination); LastTime = Game.SecondsSinceMidnight; Elapse(data); this.PluginMessage = data.DebugMessage; this.Train.Specs.DoorInterlockState = (TrainManager.DoorInterlockStates)data.DoorInterlockState; DisableTimeAcceleration = data.DisableTimeAcceleration; /* * Set the virtual handles. * */ this.PluginValid = true; SetHandles(data.Handles, true); this.Train.Destination = data.Destination; }