/// <summary>Is called when the train passes a beacon.</summary> /// <param name="data">The beacon data.</param> public void SetBeacon(BeaconData data) { switch (data.Type) { case -16777214: // ATC speed limit (.Limit command) double limit = (data.Optional & 4095); double position = (data.Optional >> 12); var item = new CompatibilityLimit(limit, position); if (!trackLimits.Contains(item)) { trackLimits.Add(item); } break; case -16777215: // ATC track compatibility ATCSection = (data.Optional >= 1 && data.Optional <= 3); break; } }
/// <summary>Is called when a beacon is passed.</summary> /// <param name="beacon">The beacon data.</param> internal override void SetBeacon(BeaconData beacon) { switch (beacon.Type) { case -16777215: if (beacon.Optional >= 0 & beacon.Optional <= 3) { this.CompatibilityState = (CompatibilityStates)beacon.Optional; } break; case -16777214: { double limit = (double)(beacon.Optional & 4095) / 3.6; double position = (beacon.Optional >> 12); CompatibilityLimit item = new CompatibilityLimit(limit, position); if (!this.CompatibilityLimits.Contains(item)) { this.CompatibilityLimits.Add(item); } } break; } }
/// <summary>Is called when a beacon is passed.</summary> /// <param name="beacon">The beacon data.</param> internal override void SetBeacon(BeaconData beacon) { if (this.State != States.Disabled & this.State != States.Suppressed & this.State != States.Initializing) { switch (beacon.Type) { case 0: case 1: // --- P -> S --- if (beacon.Optional == 0) { if (this.State == States.Normal | this.State == States.Pattern | this.State == States.Brake) { SwitchToSx(); } } break; case 3: case 4: // --- P pattern / P immediate stop --- this.Position = this.Train.State.Location; if (this.State != States.Service & this.State != States.Emergency) { if (this.State == States.Standby & (beacon.Type != 3 | beacon.Optional != -1)) { SwitchToP(States.Normal); } if (this.State != States.Standby) { double position = this.Position + beacon.Signal.Distance - this.SignalOffset; bool update = false; if (this.SignalPattern.Position == double.MaxValue) { update = true; } else if (position > this.SignalPattern.Position - 30.0) { update = true; } if (update) { if (beacon.Signal.Aspect == 0) { this.SignalPattern.SetRedSignal(position); if (beacon.Type != 3 & beacon.Signal.Distance < 50.0 & !BrakeRelease) { SwitchToP(States.Emergency); } } else { this.SignalPattern.SetGreenSignal(position); } } } } break; } } switch (beacon.Type) { case -16777213: // --- compatibility temporary pattern --- { double limit = (double)(beacon.Optional & 4095) / 3.6; double position = (beacon.Optional >> 12); CompatibilityLimit item = new CompatibilityLimit(limit, position); if (!this.CompatibilityLimits.Contains(item)) { this.CompatibilityLimits.Add(item); } } break; case -16777212: // --- compatibility permanent pattern --- if (beacon.Optional == 0) { this.CompatibilityPermanentPattern.Clear(); } else { double limit = (double)beacon.Optional / 3.6; this.CompatibilityPermanentPattern.SetLimit(limit, double.MinValue); } break; } }
/// <summary>Is called when a beacon is passed.</summary> /// <param name="beacon">The beacon data.</param> internal override void SetBeacon(BeaconData beacon) { if (this.State != States.Disabled & this.State != States.Suppressed & this.State != States.Initializing) { switch (beacon.Type) { case 0: case 1: // --- P -> S --- if (beacon.Optional == 0) { if (this.State == States.Normal | this.State == States.Pattern | this.State == States.Brake) { SwitchToSx(); } } break; case 3: case 4: // --- P pattern / P immediate stop --- this.Position = this.Train.State.Location; if (this.State != States.Service & this.State != States.Emergency) { if (this.State == States.Standby & (beacon.Type != 3 | beacon.Optional != -1)) { SwitchToP(States.Normal); } if (this.State != States.Standby) { if (beacon.Signal.Aspect == 0) { this.SignalPattern.SetSignal(this.Position + beacon.Signal.Distance - SignalOffset); if (beacon.Type != 3 & beacon.Signal.Distance < 50.0 & !BrakeRelease) { SwitchToP(States.Emergency); } } else { this.SignalPattern.Clear(); } } } break; } } switch (beacon.Type) { case -16777213: // --- compatibility temporary pattern --- { double limit = (double)(beacon.Optional & 4095) / 3.6; double position = (beacon.Optional >> 12); CompatibilityLimit item = new CompatibilityLimit(limit, position); if (!this.CompatibilityLimits.Contains(item)) { this.CompatibilityLimits.Add(item); } } break; case -16777212: // --- compatibility permanent pattern --- if (beacon.Optional == 0) { this.CompatibilityPermanentPattern.Clear(); } else { double limit = (double)beacon.Optional / 3.6; this.CompatibilityPermanentPattern.SetLimit(limit, double.MinValue); } break; } }
/// <summary>Is called when a beacon is passed.</summary> /// <param name="beacon">The beacon data.</param> internal override void SetBeacon(BeaconData beacon) { if (this.State != States.Disabled & this.State != States.Suppressed & this.State != States.Initializing) { switch (beacon.Type) { case 3: case 4: case 5: // --- P signal pattern / P immediate stop --- this.Position = this.Train.State.Location; if (this.State != States.Service & this.State != States.Emergency) { if (this.State == States.Standby & beacon.Optional != -1) { SwitchToP(States.Normal); } if (this.State != States.Standby) { double location = this.Train.State.Location + beacon.Signal.Distance; int aspect = beacon.Signal.Aspect; if (aspect < 0 | aspect >= 10) { aspect = 0; } if (aspect == 0) { const double tolerance = 5.0; bool add = true; for (int i = 0; i < this.SignalPatterns.Count; i++) { if (Math.Abs(this.SignalPatterns[i].Position - location) < tolerance) { this.SignalPatterns[i].SetRedSignal(location); add = false; } } if (add) { var pattern = new Pattern(this); pattern.SetRedSignal(location); this.SignalPatterns.Add(pattern); this.Patterns.Add(pattern); } if (!this.BrakeRelease) { if (beacon.Type == 4) { SwitchToP(States.Emergency); } else if (beacon.Type == 5) { SwitchToP(States.Service); } } } else { const double tolerance = 5.0; for (int i = 0; i < this.SignalPatterns.Count; i++) { if (Math.Abs(this.SignalPatterns[i].Position - location) < tolerance) { this.Patterns.Remove(this.SignalPatterns[i]); this.SignalPatterns[i] = this.SignalPatterns[this.SignalPatterns.Count - 1]; this.SignalPatterns.RemoveAt(this.SignalPatterns.Count - 1); i--; } } } } } break; case 6: // --- P divergence speed limit --- { int distance = beacon.Optional / 1000; if (distance > 0) { if (this.State == States.Standby) { SwitchToP(States.Normal); } this.Position = this.Train.State.Location; int speed = beacon.Optional % 1000; this.DivergencePattern.SetLimit((double)speed / 3.6, this.Position + distance); } } break; case 7: // --- P permanent speed limit --- this.Position = this.Train.State.Location; if (beacon.Optional > 0) { if (this.State == States.Standby) { SwitchToP(States.Normal); } this.RoutePermanentPattern.SetLimit((double)beacon.Optional / 3.6, double.MinValue); } else { SwitchToP(States.Emergency); } break; case 8: // --- P downslope speed limit --- { int distance = beacon.Optional / 1000; if (distance > 0) { if (this.State == States.Standby) { SwitchToP(States.Normal); } this.Position = this.Train.State.Location; int speed = beacon.Optional % 1000; this.DownslopePattern.SetLimit((double)speed / 3.6, this.Position + distance); } } break; case 9: // --- P curve speed limit --- { int distance = beacon.Optional / 1000; if (distance > 0) { if (this.State == States.Standby) { SwitchToP(States.Normal); } this.Position = this.Train.State.Location; int speed = beacon.Optional % 1000; this.CurvePattern.SetLimit((double)speed / 3.6, this.Position + distance); } } break; case 10: // --- P temporary speed limit / P->S (IIYAMA style) --- { int left = beacon.Optional / 1000; int right = beacon.Optional % 1000; if (left != 0) { if (this.State == States.Standby) { SwitchToP(States.Normal); } this.Position = this.Train.State.Location; this.TemporaryPattern.SetLimit((double)right / 3.6, this.Position + left); } else if (left == 0 & right != 0) { this.Position = this.Train.State.Location; this.SwitchToAtsSxPosition = this.Position + right; } } break; case 16: // --- P divergence limit released --- if (beacon.Optional == 0) { this.Position = this.Train.State.Location; this.DivergencePattern.Clear(); } break; case 18: // --- P downslope limit released --- if (beacon.Optional == 0) { this.Position = this.Train.State.Location; this.DownslopePattern.Clear(); } break; case 19: // --- P curve limit released --- if (beacon.Optional == 0) { this.Position = this.Train.State.Location; this.CurvePattern.Clear(); } break; case 20: // --- P temporary limit released --- if (beacon.Optional == 0) { this.Position = this.Train.State.Location; this.TemporaryPattern.Clear(); } break; case 25: // --- P/S system switch --- if (beacon.Optional == 0) { // --- Sx only --- this.Position = this.Train.State.Location; if (this.State == States.Normal | this.State == States.Pattern | this.State == States.Brake | this.State == States.Service | this.State == States.Emergency) { this.SwitchToAtsSxPosition = this.Position; } } else if (beacon.Optional == 1) { // --- P only --- this.Position = this.Train.State.Location; if (this.State == States.Standby) { SwitchToP(States.Normal); } if (this.AtsSxPMode) { this.AtsSxPMode = false; if (this.Train.AtsSx != null & !this.Blocked) { this.Train.Sounds.AtsPBell.Play(); } } } else if (beacon.Optional == 2) { // --- Sx/P --- this.Position = this.Train.State.Location; if (this.State == States.Standby) { SwitchToP(States.Normal); } if (!this.AtsSxPMode) { this.AtsSxPMode = true; if (this.Train.AtsSx != null & !this.Blocked) { this.Train.Sounds.AtsPBell.Play(); } } } break; } } switch (beacon.Type) { case -16777213: // --- compatibility temporary pattern --- { double limit = (double)(beacon.Optional & 4095) / 3.6; double position = (double)(beacon.Optional >> 12); var item = new CompatibilityLimit(limit, position); if (!this.CompatibilityLimits.Contains(item)) { this.CompatibilityLimits.Add(item); this.CompatibilityLimitsNeedsSort = true; } } break; case -16777212: // --- compatibility permanent pattern --- if (beacon.Optional == 0) { this.CompatibilityPermanentPattern.Clear(); } else { double limit = (double)beacon.Optional / 3.6; this.CompatibilityPermanentPattern.SetLimit(limit, double.MinValue); } break; } }
/// <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.CompatibilityLimitsNeedsSort) { CompatibilityLimit.Sort(this, this.CompatibilityLimits); this.CompatibilityLimitsNeedsSort = false; } this.Blocked = blocking; 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; this.BrakeRelease = false; this.SwitchToAtsSxPosition = double.MaxValue; foreach (var pattern in this.Patterns) { if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) >= pattern.WarningPattern) { pattern.Clear(); } } this.Train.Sounds.AtsPBell.Play(); } } if (BrakeRelease) { BrakeReleaseCountdown -= data.ElapsedTime.Seconds; if (BrakeReleaseCountdown <= 0.0) { 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; bool normal = true; if (this.DivergencePattern.Position > double.MinValue & this.DivergencePattern.Position < double.MaxValue) { if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) < this.DivergencePattern.BrakePattern) { double distance = this.DivergencePattern.Position - this.Position; if (distance < -50.0) { this.DivergencePattern.Clear(); } } } this.UpdateCompatibilityTemporarySpeedPattern(); foreach (var pattern in this.Patterns) { pattern.Perform(this); if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) >= pattern.WarningPattern - 1.0 / 3.6) { normal = false; } if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) >= pattern.WarningPattern) { warning = true; } if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) >= pattern.BrakePattern) { brake = true; } } for (int i = 0; i < this.SignalPatterns.Count; i++) { if (this.SignalPatterns[i].Position > double.MinValue & this.SignalPatterns[i].Position < double.MaxValue) { if (Math.Abs(data.Vehicle.Speed.MetersPerSecond) < this.DivergencePattern.BrakePattern) { double distance = this.DivergencePattern.Position - this.Position; if (distance < -50.0) { this.Patterns.Remove(this.SignalPatterns[i]); this.SignalPatterns[i] = this.SignalPatterns[this.SignalPatterns.Count - 1]; this.SignalPatterns.RemoveAt(this.SignalPatterns.Count - 1); i--; } } } } 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 & normal & (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; } } if (this.Position > this.SwitchToAtsSxPosition & this.State != States.Brake & this.State != States.Service & this.State != States.Emergency) { SwitchToSx(); } } else 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; } if (!this.AtsSxPMode & (this.State == States.Normal | this.State == States.Pattern | this.State == States.Brake | this.State == States.Service | this.State == States.Emergency)) { blocking = true; } if (this.State != States.Disabled & this.Train.Doors != DoorStates.None) { 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.State != States.Disabled & this.State != States.Suppressed & this.State != States.Standby & this.BrakeRelease) { this.Train.Panel[4] = 1; this.Train.Panel[261] = 1; } // --- debug --- if (this.State == States.Normal | this.State == States.Pattern | this.State == States.Brake | this.State == States.Service | this.State == States.Emergency) { var builder = new StringBuilder(); for (int i = 0; i < this.SignalPatterns.Count; i++) { this.SignalPatterns[i].AddToStringBuilder(i.ToString() + ":", builder); } this.DivergencePattern.AddToStringBuilder("分岐/D:", builder); this.TemporaryPattern.AddToStringBuilder("臨時/T:", builder); this.CurvePattern.AddToStringBuilder("曲線/C:", builder); this.DownslopePattern.AddToStringBuilder("勾配/S:", builder); this.RoutePermanentPattern.AddToStringBuilder("最高/Max:", builder); this.TrainPermanentPattern.AddToStringBuilder("電車/Train:", builder); if (this.SwitchToAtsSxPosition != double.MaxValue) { if (builder.Length != 0) { builder.Append(", "); } builder.Append("Sx@" + (this.SwitchToAtsSxPosition - this.Position).ToString("0")); } this.CompatibilityTemporaryPattern.AddToStringBuilder("CompTemp", builder); this.CompatibilityPermanentPattern.AddToStringBuilder("CompPerm", builder); if (builder.Length == 0) { data.DebugMessage = this.State.ToString(); } else { data.DebugMessage = this.State.ToString() + " - " + builder.ToString(); } } }