// --- constructors --- /// <summary>Creates a new instance of this class.</summary> /// <param name="vehicle">The state of the train.</param> /// <param name="precedingVehicle">The state of the preceding train, or a null reference if there is no preceding train.</param> /// <param name="handles">The virtual handles.</param> /// <param name="totalTime">The current absolute time.</param> /// <param name="elapsedTime">The elapsed time since the last call to Elapse.</param> public ElapseData(VehicleState vehicle, PrecedingVehicleState precedingVehicle, Handles handles, Time totalTime, Time elapsedTime) { this.Vehicle = vehicle; this.PrecedingVehicle = precedingVehicle; this.Handles = handles; this.TotalTime = totalTime; this.ElapsedTime = elapsedTime; this.DebugMessage = null; }
/*internal void ElapseTripTimer(ElapseData data) * { * if (atpTripTimer != null) * { * atpTripTimer -= data.ElapsedTime.Seconds; * atpTripTimer = Math.Max(atpTripTimer ?? 0, 0); * if (data.Vehicle.Speed.KilometersPerHour <= train.atpTrackSafetySpeed) * { * atpTripTimer = null; * } * } * else if (data.Vehicle.Speed.KilometersPerHour > train.atpTrackSafetySpeed) * { * atpTripTimer = ATP_WARNING_DURATION; * } * }*/ internal void UpdateAtpSpeeds(ElapseData data, PrecedingVehicleState precedingVehicle) { if (train.atpTrackNextSpeedPosition >= data.Vehicle.Location) { //Calculate braking curve to upcoming speed limit double newTargetSpeed = CalculateSpeedToStop(ATP_TARGET_DECELERATION_RATE, (train.atpTrackNextSpeedPosition - data.Vehicle.Location), train.atpTrackNextTargetSpeed); double newSafetySpeed = CalculateSpeedToStop(ATP_SAFETY_DECELERATION_RATE, (train.atpTrackNextSpeedPosition - data.Vehicle.Location), train.atpTrackNextSafetySpeed); //Select whichever speed is lower train.atpTrackTargetSpeed = Math.Min(newTargetSpeed, train.atpTrackTargetSpeed); train.atpTrackSafetySpeed = Math.Min(newSafetySpeed, train.atpTrackSafetySpeed); } if (ATP_FORCE_STATION_STOP) { if (upcomingStopLocation.HasValue) { //Calculate braking curve to upcoming station stop double newTargetSpeed = CalculateSpeedToStop(ATP_TARGET_DECELERATION_RATE, (upcomingStopLocation.Value + ATP_STATION_TARGET_DISTANCE - data.Vehicle.Location), 0); double newSafetySpeed = CalculateSpeedToStop(ATP_SAFETY_DECELERATION_RATE, (upcomingStopLocation.Value + ATP_STATION_SAFETY_DISTANCE - data.Vehicle.Location), 0); //Select whichever speed is lower train.atpTargetSpeed = Math.Min(newTargetSpeed, train.atpTrackTargetSpeed); train.atpSafetySpeed = Math.Min(newSafetySpeed, train.atpTrackSafetySpeed); } else { train.atpTargetSpeed = train.atpTrackTargetSpeed; train.atpSafetySpeed = train.atpTrackSafetySpeed; } } if (precedingVehicle != null) { if (ATP_FORCE_STATION_STOP && (upcomingStopLocation - currentLocation) > precedingVehicle.Distance) { //Calculate distance to next train 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_SAFETY_DECELERATION_RATE, (precedingVehicle.Distance - ATP_SAFETY_STOPPING_DISTANCE)), train.atpTrackSafetySpeed); if (Double.IsNaN(train.atpSafetySpeed)) { throw new ApplicationException(); } } } }
/// <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 --- this.PrecedingTrain = data.PrecedingVehicle; if (this.StateSwitch) { this.State = States.Normal; this.StateSwitch = false; } if (this.State == States.Suppressed) { if (data.Handles.BrakeNotch <= this.Train.Specs.BrakeNotches) { if (this.Train.AtsSx != null | this.Train.AtsP != null) { this.State = States.Ats; } else { this.State = States.Normal; } } } if (blocking) { if (this.State != States.Disabled & this.State != States.Suppressed) { this.State = States.Ats; } } else { if (this.State == States.Normal | this.State == States.Service | this.State == States.Emergency) { var speed = GetCurrentAtcSpeed(); if (speed != this.CurrentAtcSpeed) { this.Train.Sounds.AtcBell.Play(); } this.CurrentAtcSpeed = speed; if (speed < 0.0) { if (this.State != States.Emergency) { this.State = States.Emergency; this.Train.Sounds.AtcBell.Play(); } } else if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) > speed) { if (this.State != States.Service) { this.State = States.Service; this.Train.Sounds.AtcBell.Play(); } } else if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) < speed - 1.0 / 3.6) { if (this.State != States.Normal) { this.State = States.Normal; this.Train.Sounds.AtcBell.Play(); } } if (this.State == States.Service) { if (data.Handles.BrakeNotch < this.Train.Specs.BrakeNotches) { data.Handles.BrakeNotch = this.Train.Specs.BrakeNotches; } } 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.Ats) { this.Train.Panel[271] = 12; } else if (this.State == States.Normal | this.State == States.Service | this.State == States.Emergency) { this.Train.Panel[265] = 1; if (this.CurrentAtcSpeed < 0.0) { this.Train.Panel[271] = 0; } else { int value = this.CompatibilitySpeeds.Length - 1; for (int i = 2; i < this.CompatibilitySpeeds.Length; i++) { if (this.CompatibilitySpeeds[i] > this.CurrentAtcSpeed) { value = i - 1; break; } } this.Train.Panel[271] = value; } } if (this.State == States.Service) { this.Train.Panel[267] = 1; } else if (this.State == States.Emergency) { this.Train.Panel[268] = 1; } if (this.State != States.Disabled & this.State != States.Suppressed) { this.Train.Panel[266] = 1; } // --- manual or automatic switch --- if (ShouldSwitchToAts()) { if (this.AutomaticSwitch & Math.Abs(data.Vehicle.Speed.MetersPerSecond) < 1.0 / 3.6) { KeyDown(VirtualKeys.C1); } } else if (ShouldSwitchToAtc()) { if (this.AutomaticSwitch & Math.Abs(data.Vehicle.Speed.MetersPerSecond) < 1.0 / 3.6) { KeyDown(VirtualKeys.C2); } } }
/// <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; 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); /* * 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; } } } PrecedingVehicleState precedingVehicle; if (bestLocation != double.MaxValue) { precedingVehicle = new PrecedingVehicleState(bestLocation, bestLocation - location, new Speed(bestSpeed)); } else { precedingVehicle = null; } /* * Get the driver handles. * */ Handles handles = GetHandles(); /* * Update the plugin. * */ double totalTime = Game.SecondsSinceMidnight; double elapsedTime = Game.SecondsSinceMidnight - LastTime; ElapseData data = new ElapseData(vehicle, precedingVehicle, handles, new Time(totalTime), new Time(elapsedTime)); LastTime = Game.SecondsSinceMidnight; Elapse(data); this.PluginMessage = data.DebugMessage; /* * Set the virtual handles. * */ this.PluginValid = true; SetHandles(data.Handles, true); }