internal override int? Elapse(ElapseData data) { //Is train in RM? if(train.trainModeActual != Train.TrainModes.RestrictedManualForward && train.trainModeActual != Train.TrainModes.RestrictedManualReverse) { return null; } //Perform applications if (isForcedBraking && Math.Abs(data.Vehicle.Speed.KilometersPerHour) > RM_LIMITER_RESET_KMH) { return -train.specs.BrakeNotches; } else if (isForcedCoasting && Math.Abs(data.Vehicle.Speed.KilometersPerHour) > RM_LIMITER_RESET_KMH) { return 0; } //Check if applications are needed if (Math.Abs(data.Vehicle.Speed.KilometersPerHour) > RM_MAX_SPEED_KMH) { isForcedBraking = true; } else if (Math.Abs(data.Vehicle.Speed.KilometersPerHour) > RM_MOTOR_CUTOUT_KMH) { isForcedCoasting = true; } else { isForcedBraking = false; isForcedCoasting = false; } return null; }
internal override int? Elapse(ElapseData data) { if (trainModeNew != null) { train.trainModeSelected = (Train.TrainModes)trainModeNew; changeModeTimer = CHANGE_MODE_TIMER; trainModeNew = null; } if (train.trainModeActual != train.trainModeSelected) { if (IsModeChangable(data)) { if (changeModeTimer > 0) { changeModeTimer -= (float)data.ElapsedTime.Seconds; } else { changeModeTimer = 0.0f; train.trainModeActual = train.trainModeSelected; } } else { return -train.specs.BrakeNotches; } } return null; }
public Speed getCurrentSpeedLimit(ElapseData data) { if (decelerationControlEnabled) { double distance = System.Math.Abs(decelerationTargetDistance - (int) Math.Round(data.Vehicle.Location)); double s = (decelerationInitSpeed.MetersPerSecond / System.Math.Sqrt(2 * decelCoeff * decelerationInitLocation)) * System.Math.Sqrt(2 * decelCoeff * distance); if (decelerationType == DecelerationControlType.strong) { if (s > 4.16) /* 15 km/h */ return new Speed(s); else return new Speed(4.16); } else { if (s > 8.33) /* 30 km/h */ return new Speed(s); else return new Speed(8.33); } } else return currentSpeedLimit; }
public override void elapse(ElapseData data) { globalTime = data.TotalTime; if (!applyBreak && (data.Vehicle.Speed.KilometersPerHour > 0 || securityTest)) { if (!hold && (globalTime.Milliseconds - time.Milliseconds) > delayBeforeBreaking) { soundManager.startSound(ref vacmaHorn, SoundIndex.Vacma); if ((globalTime.Milliseconds - time.Milliseconds) > delayBeforeBreaking * 2) { applyBreak = true; soundManager.stopSound(ref vacmaHorn); handleManager.applyEmergencyBrake(); } } else if ((globalTime.Milliseconds - time.Milliseconds) > delayBeforeRinging) { soundManager.startSound(ref vacmaRing, SoundIndex.VacmaRing); if ((globalTime.Milliseconds - time.Milliseconds) > (delayBeforeRinging + delayBeforeBreaking)) { applyBreak = true; soundManager.stopSound(ref vacmaRing); handleManager.applyEmergencyBrake(); } } } else time = globalTime; }
internal override void Elapse(ElapseData data) { #if !DEBUG try { #endif this.Api.Elapse(data); for (int i = 0; i < this.SoundHandlesCount; i++) { if (this.SoundHandles[i].Stopped | this.SoundHandles[i].Source.State == Sounds.SoundSourceState.Stopped) { this.SoundHandles[i].Stop(); this.SoundHandles[i].Source.Stop(); this.SoundHandles[i] = this.SoundHandles[this.SoundHandlesCount - 1]; this.SoundHandlesCount--; i--; } else { this.SoundHandles[i].Source.Pitch = Math.Max(0.01, this.SoundHandles[i].Pitch); this.SoundHandles[i].Source.Volume = Math.Max(0.0, this.SoundHandles[i].Volume); } } #if !DEBUG } catch (Exception ex) { base.LastException = ex; throw; } #endif }
internal override int? Elapse(ElapseData data) { //Calculate signalling status //Distance to next train UpdateAtpSpeeds(data, data.PrecedingVehicle); //Check trip count //Check for speed limits ElapseTripTimer(data); //Is train in RM? if (train.trainModeActual == Train.TrainModes.RestrictedManualForward || train.trainModeActual == Train.TrainModes.RestrictedManualReverse || train.trainModeActual == Train.TrainModes.Off) { atpState = AtpStates.Off; } switch (atpState) { case AtpStates.Active: if (atpTripTimer <= 0.0) { atpState = AtpStates.Tripped; } return null; case AtpStates.Tripped: return -train.specs.BrakeNotches - 1; default: return null; } }
internal void Elapse(ElapseData data) { vState = data; if (data.TotalTime.Milliseconds - lastTotalTimeSendElapseData >= 1000) { timsPipeServer.SendObject(data); lastTotalTimeSendElapseData = data.TotalTime.Milliseconds; } }
/// <summary>Is called every frame.</summary> /// <param name="data">The data passed to the plugin.</param> public void Elapse(ElapseData data) { closedSignalDevice.elapse(data); vacma.elapse(data); speedControl.elapse(data); handleManager.elapse(ref data); soundManager.elapse(data); cabControlManager.elapse(data); }
/// <summary>Is called every frame.</summary> /// <param name="data">The data passed to the plugin.</param> public void Elapse(ElapseData data) { ms.Elapse(data); tims.Elapse(data); Panel[PanelID.ActualHandle.Reverser] = data.Handles.Reverser; Panel[PanelID.ActualHandle.Power] = data.Handles.PowerNotch; Panel[PanelID.ActualHandle.Brake] = data.Handles.BrakeNotch; Panel[PanelID.ActualHandle.ConstSpd] = data.Handles.ConstSpeed ? 1 : 0; }
internal void Elapse(ElapseData vState) { Panel[PanelID.StatusLEDs.NoSignal] = 0; if (Stations.Count > 0) { if (lastCompletedDockingIndex > 0 && Stations[lastCompletedDockingIndex].TBSStart && doorCls) { // can operate in driverless using ATO OnDriverlessAvailableElapse(vState); } } }
/// <summary>Is called every frame.</summary> /// <param name="data">The data passed to the plugin.</param> public void Elapse(ElapseData data) { /* * How to access panel variables: * Panel[i] = 1; * * How to access sound variables: * Sound[i] = SoundInstructions.PlayOnce; * */ // TODO: Your old Elapse code goes here. Sound.Update(); }
public void elapse(ElapseData data) { globalTime = data.TotalTime; loopSoundsFor.ForEach(delegate (LoopSoundFor sound) { if (globalTime.Milliseconds - sound.start > sound.duration) { sound.sound.Stop(); loopSoundsFor.Remove(sound); } }); }
internal void Elapse(ElapseData data) { vState = data; stationsMemory.Elapse(data); #region Reset status LEDs Panel[PanelID.StatusLEDs.ATO] = 0; Panel[PanelID.StatusLEDs.ATP] = 0; Panel[PanelID.StatusLEDs.RM] = 0; Panel[PanelID.StatusLEDs.RM_Reverse] = 0; Panel[PanelID.StatusLEDs.HKHR_ATP] = 0; Panel[PanelID.StatusLEDs.NoSignal] = 0; #endregion #region reset ATP lamps to off if not using if ((int)currentMode < (int)Modes.PM) atp2.NotElapsing(); #endregion // give privilege of controlling the train to different classes(modules) by state of mode currently using switch (currentMode) { case ModeSelector.Modes.Off: vState.Handles.Reverser = 0; vState.Handles.PowerNotch = 0; vState.Handles.BrakeNotch = vSpec.BrakeNotches + 1; driverless.Elapse(vState); break; case ModeSelector.Modes.RM_B: vState.Handles.Reverser = -1; vState.Handles.PowerNotch = handlePower; vState.Handles.BrakeNotch = handleBrake; rm.Elapse(vState); break; case ModeSelector.Modes.RM_F: vState.Handles.Reverser = 1; vState.Handles.PowerNotch = handlePower; vState.Handles.BrakeNotch = handleBrake; rm.Elapse(vState); break; case ModeSelector.Modes.PM: vState.Handles.Reverser = 1; vState.Handles.PowerNotch = handlePower; vState.Handles.BrakeNotch = handleBrake; Panel[PanelID.StatusLEDs.ATP] = 1; atp2.Elapse(vState); break; case ModeSelector.Modes.AM: vState.Handles.Reverser = 1; Panel[PanelID.StatusLEDs.ATO] = 1; ato.Elapse(atp2.Elapse(vState)); break; } }
internal override int? Elapse(ElapseData data) { if(this.train.doorState != DoorStates.None) { if(Math.Abs(data.Vehicle.Speed.KilometersPerHour) > 0.2) { return -this.train.specs.BrakeNotches - 1; } else { return -this.train.specs.BrakeNotches; } } return null; }
internal int CalculateStationStopNotchChange(ElapseData data, double distanceToNextStop) { //Returns notch adjustment double speed = data.Vehicle.Speed.MetersPerSecond; if (speed > ATO_LEVELLING_SPEED) { double stoppingDistance = CalculateDecelerationDistance(data.Vehicle.Speed.MetersPerSecond, ATO_TARGET_DECELERATION_RATE) ?? 0; if (stoppingDistance < distanceToNextStop - ATO_LEVELLING_DISTANCE - ATO_BRAKING_TOLERANCE) { return 1; } else if (stoppingDistance > distanceToNextStop - ATO_LEVELLING_DISTANCE + ATO_BRAKING_TOLERANCE) { return -1; } else { return 0; } } else { double stoppingDistance = CalculateDecelerationDistance(data.Vehicle.Speed.MetersPerSecond, ATO_LEVELLING_DECELERATION_RATE) ?? 0; if (stoppingDistance < distanceToNextStop - ATO_LEVELLING_TOLERANCE) { if(data.Vehicle.Speed.MetersPerSecond > ATO_LEVELLING_CRAWL_SPEED && atoDemands >= 0) { return 0; } else { return 1; } } else if (stoppingDistance > distanceToNextStop + ATO_LEVELLING_TOLERANCE) { return -1; } else { return 0; } } }
internal void Elapse(ElapseData data) { Panel[PanelID.StatusLEDs.NoSignal] = 1; // assume as no signal Panel[PanelID.StatusLEDs.RM] = 1; // in RM mode Panel[PanelID.StatusLEDs.RM_Reverse] = data.Handles.Reverser == -1 ? 1 : 0; // in RM-B mode? if (data.Vehicle.Speed.KilometersPerHour > 45 || data.Vehicle.Speed.KilometersPerHour > SignalSpeed[(int)currentSignalPost]) { data.Handles.PowerNotch = 0; data.Handles.BrakeNotch = vSpec.BrakeNotches; BrakeInForce = true; } else if (BrakeInForce && data.Vehicle.Speed.KilometersPerHour <= SignalCoastingSpeed[(int)currentSignalPost]) { data.Handles.PowerNotch = 0; data.Handles.BrakeNotch = 0; } else if (!BrakeInForce && data.Vehicle.Speed.KilometersPerHour > SignalCoastingSpeed[(int)currentSignalPost]) { data.Handles.PowerNotch = 0; data.Handles.BrakeNotch = 0; } }
// --- functions --- /// <summary>Is called every frame.</summary> /// <param name="data">The data.</param> internal void Elapse(ElapseData data) { foreach (Sound sound in this.LoopingSounds) { if (sound.IsToBePlayed) { if (sound.Handle == null || sound.Handle.Stopped) { sound.Handle = PlaySound(sound.Index, 1.0, 1.0, true); } } else { if (sound.Handle != null && sound.Handle.Playing) { sound.Handle.Stop(); } } sound.IsToBePlayed = false; } foreach (Sound sound in this.PlayOnceSounds) { if (sound.IsToBePlayed) { PlaySound(sound.Index, 1.0, 1.0, false); sound.IsToBePlayed = false; } } }
/// <summary>Is called every frame.</summary> /// <param name="data">The data.</param> /// <param name="blocking">Whether the device is blocked or will block subsequent devices.</param> internal override void Elapse(ElapseData data, ref bool blocking) { // --- behavior --- if (!blocking) { if (Math.Abs(data.Vehicle.Speed.KilometersPerHour) > SpeedThreshold | this.Counter >= TimeUntilBell) { this.Counter += data.ElapsedTime.Seconds; if (this.Counter >= TimeUntilBrake) { if (this.Train.AtsSx != null) { if (this.Train.AtsSx.State != AtsSx.States.Disabled) { this.Train.AtsSx.State = AtsSx.States.Emergency; if (this.Train.AtsP != null && (this.Train.AtsP.State == AtsP.States.Normal | this.Train.AtsP.State == AtsP.States.Pattern | this.Train.AtsP.State == AtsP.States.Brake | this.Train.AtsP.State == AtsP.States.Service | this.Train.AtsP.State == AtsP.States.Emergency)) { this.Train.AtsP.State = AtsP.States.Standby; } if (this.Train.Atc != null && (this.Train.Atc.State == Atc.States.Normal | this.Train.Atc.State == Atc.States.Service | this.Train.Atc.State == Atc.States.Emergency)) { this.Train.Atc.State = Atc.States.Ats; } this.Counter = 0.0; } } else { this.Train.Sounds.AtsBell.Play(); data.Handles.BrakeNotch = this.Train.Specs.BrakeNotches + 1; } } else if (this.Counter >= TimeUntilBell) { this.Train.Sounds.Eb.Play(); } } else { this.Counter = 0.0; } } else { this.Counter = 0.0; } // --- panel --- if (this.Counter >= TimeUntilBrake) { int value = (int)data.TotalTime.Milliseconds % 1000 < 500 ? 1 : 0; this.Train.Panel[8] = value; this.Train.Panel[270] = value; } else if (this.Counter >= TimeUntilBell) { this.Train.Panel[8] = 1; this.Train.Panel[270] = 1; } }
// --- functions --- /// <summary>Updates the pattern.</summary> /// <param name="system">The current ATS-P system.</param> /// <param name="data">The elapse data.</param> internal void Perform(AtsP system, ElapseData data) { if (this.Position == double.MaxValue | this.TargetSpeed == double.MaxValue) { this.WarningPattern = double.MaxValue; this.BrakePattern = double.MaxValue; } else if (this.Position == double.MinValue) { this.WarningPattern = this.TargetSpeed - this.Device.PatternSpeedDifference; this.BrakePattern = Math.Max(this.TargetSpeed, this.Device.ReleaseSpeed); } else { const double earthGravity = 9.81; double accelerationDueToGravity = earthGravity * this.Gradient / Math.Sqrt(1.0 + this.Gradient * this.Gradient); double deceleration = this.Device.DesignDeceleration + accelerationDueToGravity; double distance = this.Position - system.Position; /* * Calculate the warning pattern. * */ { double sqrtTerm = 2.0 * deceleration * (distance - 50.0) + deceleration * deceleration * this.Device.ReactionDelay * this.Device.ReactionDelay + this.TargetSpeed * this.TargetSpeed; if (sqrtTerm <= 0.0) { this.WarningPattern = this.TargetSpeed - this.Device.PatternSpeedDifference; } else { this.WarningPattern = Math.Max(Math.Sqrt(sqrtTerm) - deceleration * this.Device.ReactionDelay, this.TargetSpeed - this.Device.PatternSpeedDifference); } } /* * Calculate the brake pattern. * */ { double sqrtTerm = 2.0 * deceleration * distance + this.TargetSpeed * this.TargetSpeed; if (sqrtTerm <= 0.0) { this.BrakePattern = this.TargetSpeed; } else { this.BrakePattern = Math.Max(Math.Sqrt(sqrtTerm), TargetSpeed); } if (this.BrakePattern < this.Device.ReleaseSpeed) { this.BrakePattern = this.Device.ReleaseSpeed; } } } }
/// <summary>Is called every frame.</summary> /// <param name="data">The data.</param> /// <param name="blocking">Whether the device is blocked or will block subsequent devices.</param> internal override void Elapse(ElapseData data, ref bool blocking) { // --- behavior --- if (this.State == States.Suppressed) { if (data.Handles.BrakeNotch <= this.Train.Specs.BrakeNotches) { this.AlarmCountdown = DurationOfInitialization; this.State = States.Initializing; } } if (this.State == States.Initializing) { this.AlarmCountdown -= data.ElapsedTime.Seconds; if (this.AlarmCountdown <= 0.0) { this.State = States.Chime; } else { data.Handles.BrakeNotch = this.Train.Specs.BrakeNotches + 1; this.Train.Sounds.AtsBell.Play(); } } if (blocking) { if (this.State != States.Disabled & this.State != States.Suppressed) { this.State = States.Normal; } } else { if (this.State == States.Chime) { this.Train.Sounds.AtsChime.Play(); } else if (this.State == States.Alarm) { this.Train.Sounds.AtsBell.Play(); this.AlarmCountdown -= data.ElapsedTime.Seconds; if (this.AlarmCountdown <= 0.0) { this.State = States.Emergency; } } else if (this.State == States.Emergency) { this.Train.Sounds.AtsBell.Play(); data.Handles.BrakeNotch = this.Train.Specs.BrakeNotches + 1; } if (this.SpeedCheckCountdown > 0.0 & data.ElapsedTime.Seconds > 0.0) { this.SpeedCheckCountdown -= data.ElapsedTime.Seconds; } if (this.CompatibilityDistanceAccumulator != 0.0) { this.CompatibilityDistanceAccumulator += data.Vehicle.Speed.MetersPerSecond * data.ElapsedTime.Seconds; if (this.CompatibilityDistanceAccumulator > 27.7) { this.CompatibilityDistanceAccumulator = 0.0; } } if (this.State != States.Disabled & (this.Train.Doors != DoorStates.None | data.Handles.BrakeNotch > 0)) { data.Handles.PowerNotch = 0; } } // --- panel --- if ((this.State == States.Chime | this.State == States.Normal) & !blocking) { this.Train.Panel[256] = 1; } if (this.State == States.Initializing | this.State == States.Alarm) { this.Train.Panel[257] = 1; this.Train.Panel[258] = 1; } else if (this.State == States.Emergency) { int value = (int)data.TotalTime.Milliseconds % 1000 < 500 ? 1 : 0; this.Train.Panel[257] = 2; this.Train.Panel[258] = value; } }
/// <summary>Called every frame to update the plugin.</summary> /// <param name="data">The data passed to the plugin on Elapse.</param> /// <remarks>This function should not be called directly. Call UpdatePlugin instead.</remarks> internal abstract void Elapse(ElapseData data);
/// <summary>Called every frame to update the plugin.</summary> internal void UpdatePlugin() { /* * Prepare the vehicle state. * */ double location = this.Train.Cars[0].FrontAxle.Follower.TrackPosition - this.Train.Cars[0].FrontAxlePosition + 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>(); foreach (Game.Station selectedStation in Game.Stations) { Station i = new Station { Name = selectedStation.Name, ArrivalTime = selectedStation.ArrivalTime, DepartureTime = selectedStation.DepartureTime, StopTime = selectedStation.StopTime, OpenLeftDoors = selectedStation.OpenLeftDoors, OpenRightDoors = selectedStation.OpenRightDoors, ForceStopSignal = selectedStation.ForceStopSignal, DefaultTrackPosition = selectedStation.DefaultTrackPosition }; currentRouteStations.Add(i); } 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; for (int i = 0; i < TrainManager.Trains.Length; i++) { if (TrainManager.Trains[i] != this.Train & TrainManager.Trains[i].State == TrainManager.TrainState.Available) { int c = TrainManager.Trains[i].Cars.Length - 1; double z = TrainManager.Trains[i].Cars[c].RearAxle.Follower.TrackPosition - TrainManager.Trains[i].Cars[c].RearAxlePosition - 0.5 * TrainManager.Trains[i].Cars[c].Length; if (z >= location & z < bestLocation) { bestLocation = z; bestSpeed = TrainManager.Trains[i].Specs.CurrentAverageSpeed; } } } var precedingVehicle = bestLocation != double.MaxValue ? new PrecedingVehicleState(bestLocation, bestLocation - location, new Speed(bestSpeed)) : 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 = (OpenBveApi.Runtime.CameraViewMode)World.CameraMode; ElapseData data = new ElapseData(vehicle, precedingVehicle, handles, new Time(totalTime), new Time(elapsedTime), currentRouteStations, CurrentCameraViewMode, Interface.CurrentLanguageCode); LastTime = Game.SecondsSinceMidnight; Elapse(data); this.PluginMessage = data.DebugMessage; DisableTimeAcceleration = data.DisableTimeAcceleration; /* * Set the virtual handles. * */ this.PluginValid = true; SetHandles(data.Handles, true); }
/// <summary>Is called every frame.</summary> /// <param name="data">The data.</param> internal void Elapse(ElapseData data) { this.PluginInitializing = false; if (data.ElapsedTime.Seconds > 0.0 & data.ElapsedTime.Seconds < 1.0) { // --- panel --- for (int i = 0; i < this.Panel.Length; i++) { this.Panel[i] = 0; } // --- devices --- this.State = data.Vehicle; this.Handles = new ReadOnlyHandles(data.Handles); bool blocking = false; foreach (Device device in this.Devices) { device.Elapse(data, ref blocking); } // --- panel --- int seconds = (int)Math.Floor(data.TotalTime.Seconds); this.Panel[10] = (seconds / 3600) % 24; this.Panel[11] = (seconds / 60) % 60; this.Panel[12] = seconds % 60; this.Panel[269] = data.Handles.ConstSpeed ? 1 : 0; if (data.Handles.Reverser != 0 & (this.Handles.PowerNotch > 0 & this.Handles.BrakeNotch == 0 | this.Handles.PowerNotch == 0 & this.Handles.BrakeNotch == 1 & this.Specs.HasHoldBrake)) { this.Panel[100] = 1; } if (data.Handles.BrakeNotch >= this.Specs.AtsNotch & data.Handles.BrakeNotch <= this.Specs.BrakeNotches | data.Handles.Reverser != 0 & data.Handles.BrakeNotch == 1 & this.Specs.HasHoldBrake) { this.Panel[101] = 1; } // --- sound --- this.Sounds.Elapse(data); } }
/// <summary>Creates a new ElapseProxy from an ElapseData</summary> public ElapseProxy(ElapseData data, int[] panel, int[] sound) { this.Data = data; Panel = panel; Sound = sound; }
internal double UpdateAcceleration(ElapseData data) { double speedPrev = accelerationLastSpeed; double speedNow = data.Vehicle.Speed.MetersPerSecond; double time = (data.TotalTime.Seconds - accelerationLastPoll.Seconds); accelerationRate = (speedNow - speedPrev) / time; accelerationLastPoll = data.TotalTime; accelerationLastSpeed = speedNow; return accelerationRate; }
internal void UpdateAtpSpeeds(ElapseData data, PrecedingVehicleState precedingVehicle) { if(precedingVehicle == null) { train.atpTargetSpeed = train.atpTrackTargetSpeed; train.atpSafetySpeed = train.atpTrackSafetySpeed; } else { double distanceToStop = precedingVehicle.Distance - ATP_TARGET_STOPPING_DISTANCE; train.atpTargetSpeed = Math.Max(Math.Min(CalculateSpeedToStop(ATP_TARGET_DECELERATION_RATE, distanceToStop), train.atpTrackTargetSpeed), 0.0); if(Double.IsNaN(train.atpTargetSpeed)) { throw new ApplicationException(); } train.atpSafetySpeed = Math.Min(CalculateSpeedToStop(ATP_TARGET_DECELERATION_RATE, (precedingVehicle.Distance - ATP_SAFETY_STOPPING_DISTANCE)), train.atpTrackSafetySpeed); if (Double.IsNaN(train.atpSafetySpeed)) { throw new ApplicationException(); } } }
internal override int? Elapse(ElapseData data) { train.debugMessage = ""; //Is train in Auto? if (train.trainModeActual != Train.TrainModes.Auto) { atoState = AtoStates.Stopped; return null; } //Calculate current acceleration rate if (data.TotalTime.Seconds - accelerationLastPoll.Seconds >= ACCELERATION_POLL_RATE) { UpdateAcceleration(data); } //Calculate distance to stop double? distanceToNextStop = null; if (atoStoppingPosition != null) { distanceToNextStop = atoStoppingPosition - data.Vehicle.Location; } train.debugMessage = $"{atoState}"; if (atoState == AtoStates.Ready) { //At station counting down to departure atoDemands = -train.specs.BrakeNotches; readyTimer -= data.ElapsedTime.Seconds; if (train.doorState != DoorStates.None) { atoState = AtoStates.Stopped; } else if (readyTimer <= 0.0) { atoState = AtoStates.Enroute; } } else if (atoState == AtoStates.Enroute) { //Travelling to next station //Get the train to stick to the ATP Target Speed int atoTargetSpeedDemand = CalculateTargetSpeedNotchChange(data); //Run function for stopping at station int? atoStoppingDemand = null; if (atoStoppingPosition != null) { //Call a function that returns the desired brake/power notch (or null if none) atoStoppingDemand = CalculateStationStopNotchChange(data, distanceToNextStop ?? 0); } //Select the lowest notch between "TASC" and the target speed code above int notch = (atoDemands ?? 0) + Math.Min(atoStoppingDemand ?? train.specs.PowerNotches, atoTargetSpeedDemand); //Call ChangeAtoDemands with appropriate time between notch ChangeAtoDemands(data, notch, ATO_TIME_BETWEEN_NOTCH_CHANGE, true, true); train.debugMessage = $"Enroute. TS {atoTargetSpeedDemand}, TASC {atoStoppingDemand}. Req {notch}. Actual {atoDemands}. Target speed {train.atpTargetSpeed}"; //If doors open if (train.doorState != DoorStates.None) { atoState = AtoStates.Stopped; } } else if (atoState == AtoStates.Stopped) { atoStoppingPosition = null; atoDemands = -train.specs.BrakeNotches; if (train.doorState == DoorStates.None) { atoState = AtoStates.Ready; readyTimer = ATO_READY_TIMER; } } if (atoReceivedData != null) { atoStoppingPosition = atoReceivedData + data.Vehicle.Location; atoReceivedData = null; } //train.debugMessage = $" Ato: {atoState} demanding {atoDemands} for {train.atpTargetSpeed}"; return atoDemands; }
/*internal int CalculateStationStop(ElapseData data, double tolerence, double targetStoppingPosition) { double projectedStoppingPosition = data.Vehicle.Location + CalculateDistanceToStop(accelerationRate, data.Vehicle.Speed.MetersPerSecond); if (projectedStoppingPosition > targetStoppingPosition || accelerationRate > 0) { return -1; } else if (projectedStoppingPosition < (targetStoppingPosition - tolerence)) { return 1; } else { return 0; } }*/ internal bool ChangeAtoDemands(ElapseData data, int newNotch, double frequency, bool clampToServiceBraking = true, bool clampToTargetDecelerationRate = false) { double currentTime = data.TotalTime.Seconds; if (currentTime - notchLastChange >= frequency) { int newDemand = Math.Max((int)atoDemands - 1, Math.Min((int)atoDemands + 1, newNotch)); if (clampToTargetDecelerationRate && accelerationRate < ATO_TARGET_DECELERATION_RATE) { newDemand++; } int min = -train.specs.BrakeNotches; if (!clampToServiceBraking) { min -= 1; } int max = train.specs.PowerNotches; atoDemands = Math.Max(min, Math.Min(max, newDemand)); notchLastChange = currentTime; train.debugMessage += $" {newNotch}"; return true; } return false; }
internal int CalculateTargetSpeedNotchChange(ElapseData data) { double speedDifference = train.atpTargetSpeed - data.Vehicle.Speed.KilometersPerHour; if (train.atpTargetSpeed <= 3.0 && data.Vehicle.Speed.KilometersPerHour <= 3.0) { return -1; } else if (train.atpTargetSpeed < data.Vehicle.Speed.KilometersPerHour) { int notch = Math.Min(0, (int)(speedDifference / ATO_BRAKING_AMOUNT) - 1); return notch - atoDemands??0; } else { int notch = Math.Max(0, (int)(speedDifference / ATO_POWERING_AMOUNT)); return notch - atoDemands??0; } }
public void Elapse(ElapseData data) { vState = data; // if stop mem has data if (Stations.Count > 0) { // if next stop is in range if (lastCompletedDockingIndex + 1 < Stations.Count) { // if next stop is passing stop if (Stations[lastCompletedDockingIndex + 1].DoorOpen == -2 && vState.Vehicle.Location >= Stations[lastCompletedDockingIndex + 1].StopPosition) { lastCompletedDockingIndex++; } // if next stop is a stop which does not need to open doors else if (vState.Vehicle.Speed.KilometersPerHour == 0 && Stations[lastCompletedDockingIndex + 1].DoorOpen == 0 && vState.Vehicle.Location >= Stations[lastCompletedDockingIndex + 1].StopPosition - StopAndDepartStopsErrorRange && vState.Vehicle.Location <= Stations[lastCompletedDockingIndex + 1].StopPosition + StopAndDepartStopsErrorRange) { lastCompletedDockingIndex++; } // passed a station/stop which should stop if (vState.Vehicle.Location > Stations[lastCompletedDockingIndex + 1].StopPosition + IllegalPassStopForceJumpRange) { // System.Windows.Forms.MessageBox.Show("passed a stop"); lastCompletedDockingIndex++; } } // display distance to next stop double distance = lastCompletedDockingIndex < Stations.Count ? Stations[lastCompletedDockingIndex + 1].StopPosition - vState.Vehicle.Location : -999; if (distance == -999) { Panel[PanelID.DistanceToNextStation.FirstDigit] = 12; Panel[PanelID.DistanceToNextStation.SecondDigit] = 12; Panel[PanelID.DistanceToNextStation.ThirdDigit] = 11; Panel[PanelID.DistanceToNextStation.ForthDigit] = 12; Panel[PanelID.DistanceToNextStation.Unit] = 1; } else if (distance >= 1000) { if (distance >= 10000) { string kmStr = Math.Round(distance/1000).ToString().PadLeft(4); Panel[PanelID.DistanceToNextStation.FirstDigit] = kmStr.Substring(0,1) == " " ? 11 : Convert.ToInt32(kmStr.Substring(0,1)); Panel[PanelID.DistanceToNextStation.SecondDigit] = kmStr.Substring(1,1) == " " ? 11 : Convert.ToInt32(kmStr.Substring(1,1)); Panel[PanelID.DistanceToNextStation.ThirdDigit] = kmStr.Substring(2,1) == " " ? 11 : Convert.ToInt32(kmStr.Substring(2,1)); Panel[PanelID.DistanceToNextStation.ForthDigit] = Convert.ToInt32(kmStr.Substring(3,1)); } else { string kmStr = Math.Round(distance/1000, 1).ToString().PadLeft(4); Panel[PanelID.DistanceToNextStation.FirstDigit] = kmStr.Substring(0,1) == " " ? 11 : Convert.ToInt32(kmStr.Substring(0,1)); Panel[PanelID.DistanceToNextStation.SecondDigit] = kmStr.Substring(1,1) == " " ? 11 : Convert.ToInt32(kmStr.Substring(1,1)); Panel[PanelID.DistanceToNextStation.ThirdDigit] = kmStr.Substring(2,1) == " " ? 11 : kmStr.Substring(2,1) == "." ? 10 : Convert.ToInt32(kmStr.Substring(2,1)); Panel[PanelID.DistanceToNextStation.ForthDigit] = Convert.ToInt32(kmStr.Substring(3,1)); } Panel[PanelID.DistanceToNextStation.Unit] = 1; } else if (Math.Abs(distance) < 10) { string mStr = Math.Round(distance, 1).ToString("0.0").PadLeft(4); Panel[PanelID.DistanceToNextStation.FirstDigit] = mStr.Substring(0,1) == "-" ? 12 : 11; Panel[PanelID.DistanceToNextStation.SecondDigit] = mStr.Substring(1,1) == "-" ? 12 : mStr.Substring(1,1) == " " ? 11 : Convert.ToInt32(mStr.Substring(1,1)); Panel[PanelID.DistanceToNextStation.ThirdDigit] = mStr.Substring(1,1) == "-" ? 12 : 10; Panel[PanelID.DistanceToNextStation.ForthDigit] = mStr.Substring(3,1) == " " ? 11 : Convert.ToInt32(mStr.Substring(3,1)); Panel[PanelID.DistanceToNextStation.Unit] = 0; } else { string mStr = Math.Round(distance).ToString().PadLeft(4); Panel[PanelID.DistanceToNextStation.FirstDigit] = 11; Panel[PanelID.DistanceToNextStation.SecondDigit] = mStr.Substring(1,1) == "-" ? 12 : mStr.Substring(1,1) == " " ? 11 : Convert.ToInt32(mStr.Substring(1,1)); Panel[PanelID.DistanceToNextStation.ThirdDigit] = Convert.ToInt32(mStr.Substring(2,1)); Panel[PanelID.DistanceToNextStation.ForthDigit] = Convert.ToInt32(mStr.Substring(3,1)); Panel[PanelID.DistanceToNextStation.Unit] = 0; } } }
/// <summary>Is called every frame.</summary> /// <param name="data">The data.</param> /// <param name="blocking">Whether the device is blocked or will block subsequent devices.</param> internal override void Elapse(ElapseData data, ref bool blocking) { // --- behavior --- if (this.State == States.Suppressed) { if (data.Handles.BrakeNotch <= this.Train.Specs.BrakeNotches) { this.InitializationCountdown = DurationOfInitialization; this.State = States.Initializing; } } if (this.State == States.Initializing) { this.InitializationCountdown -= data.ElapsedTime.Seconds; if (this.InitializationCountdown <= 0.0) { this.State = States.Standby; foreach (Pattern pattern in this.Patterns) { if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) >= pattern.WarningPattern) { pattern.Clear(); } } this.Train.Sounds.AtsPBell.Play(); } } if (this.BrakeRelease) { this.BrakeReleaseCountdown -= data.ElapsedTime.Seconds; if (this.BrakeReleaseCountdown <= 0.0) { this.BrakeRelease = false; this.Train.Sounds.AtsPBell.Play(); } } if (this.State != States.Disabled & this.State != States.Initializing) { this.Position += data.Vehicle.Speed.MetersPerSecond * data.ElapsedTime.Seconds; } if (blocking) { if (this.State != States.Disabled & this.State != States.Suppressed) { this.State = States.Standby; } } else { if (this.State == States.Normal | this.State == States.Pattern | this.State == States.Brake) { bool brake = false; bool warning = false; UpdateCompatibilityTemporarySpeedPattern(); foreach (Pattern pattern in this.Patterns) { pattern.Perform(this, data); if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) >= pattern.WarningPattern) { warning = true; } if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) >= pattern.BrakePattern) { brake = true; } } if (BrakeRelease) { brake = false; } if (brake & this.State != States.Brake) { this.State = States.Brake; this.Train.Sounds.AtsPBell.Play(); } else if (warning & this.State == States.Normal) { this.State = States.Pattern; this.Train.Sounds.AtsPBell.Play(); } else if (!brake & !warning & (this.State == States.Pattern | this.State == States.Brake)) { this.State = States.Normal; this.Train.Sounds.AtsPBell.Play(); } if (this.State == States.Brake) { if (data.Handles.BrakeNotch < this.Train.Specs.BrakeNotches) { data.Handles.BrakeNotch = this.Train.Specs.BrakeNotches; } } blocking = true; } else if (this.State == States.Service) { if (data.Handles.BrakeNotch < this.Train.Specs.BrakeNotches) { data.Handles.BrakeNotch = this.Train.Specs.BrakeNotches; } blocking = true; } else if (this.State == States.Emergency) { data.Handles.BrakeNotch = this.Train.Specs.BrakeNotches + 1; blocking = true; } if (this.State != States.Disabled & (this.Train.Doors != DoorStates.None | data.Handles.BrakeNotch > 0)) { data.Handles.PowerNotch = 0; } } // --- panel --- if (this.State != States.Disabled & this.State != States.Suppressed) { this.Train.Panel[2] = 1; this.Train.Panel[259] = 1; } if (this.State == States.Pattern | this.State == States.Brake | this.State == States.Service | this.State == States.Emergency) { this.Train.Panel[3] = 1; this.Train.Panel[260] = 1; } if (this.State == States.Brake | this.State == States.Service | this.State == States.Emergency) { this.Train.Panel[5] = 1; this.Train.Panel[262] = 1; } if (this.State != States.Disabled & this.State != States.Suppressed & this.State != States.Standby) { this.Train.Panel[6] = 1; this.Train.Panel[263] = 1; } if (this.State == States.Initializing) { this.Train.Panel[7] = 1; this.Train.Panel[264] = 1; } if (this.State == States.Disabled) { this.Train.Panel[50] = 1; } if (this.BrakeRelease) { this.Train.Panel[4] = 1; this.Train.Panel[261] = 1; } }