1 using OpenBveApi.Interface; 2 using OpenBveApi.Runtime; 3 using TrainManager.Car; 4 5 namespace TrainManager.Trains 6 { 7 public partial class TrainBase 8 { 9 /// <inheritdoc/> OpenDoors(bool Left, bool Right)10 public override void OpenDoors(bool Left, bool Right) 11 { 12 bool sl = false, sr = false; 13 for (int i = 0; i < Cars.Length; i++) 14 { 15 if (Left & !Cars[i].Doors[0].AnticipatedOpen & (SafetySystems.DoorInterlockState == DoorInterlockStates.Left | SafetySystems.DoorInterlockState == DoorInterlockStates.Unlocked)) 16 { 17 Cars[i].Doors[0].AnticipatedOpen = true; 18 sl = true; 19 } 20 21 if (Right & !Cars[i].Doors[1].AnticipatedOpen & (SafetySystems.DoorInterlockState == DoorInterlockStates.Right | SafetySystems.DoorInterlockState == DoorInterlockStates.Unlocked)) 22 { 23 Cars[i].Doors[1].AnticipatedOpen = true; 24 sr = true; 25 } 26 } 27 28 if (sl) 29 { 30 for (int i = 0; i < Cars.Length; i++) 31 { 32 Cars[i].Doors[0].OpenSound.Play(Cars[i].Specs.DoorOpenPitch, 1.0, Cars[i], false); 33 for (int j = 0; j < Cars[i].Doors.Length; j++) 34 { 35 if (Cars[i].Doors[j].Direction == -1) 36 { 37 Cars[i].Doors[j].DoorLockDuration = 0.0; 38 } 39 } 40 } 41 } 42 43 if (sr) 44 { 45 for (int i = 0; i < Cars.Length; i++) 46 { 47 Cars[i].Doors[1].OpenSound.Play(Cars[i].Specs.DoorOpenPitch, 1.0, Cars[i], false); 48 for (int j = 0; j < Cars[i].Doors.Length; j++) 49 { 50 if (Cars[i].Doors[j].Direction == 1) 51 { 52 Cars[i].Doors[j].DoorLockDuration = 0.0; 53 } 54 } 55 } 56 } 57 } 58 59 /// <inheritdoc/> CloseDoors(bool Left, bool Right)60 public override void CloseDoors(bool Left, bool Right) 61 { 62 bool sl = false, sr = false; 63 for (int i = 0; i < Cars.Length; i++) 64 { 65 if (Left & Cars[i].Doors[0].AnticipatedOpen & (SafetySystems.DoorInterlockState == DoorInterlockStates.Left | SafetySystems.DoorInterlockState == DoorInterlockStates.Unlocked)) 66 { 67 Cars[i].Doors[0].AnticipatedOpen = false; 68 sl = true; 69 } 70 71 if (Right & Cars[i].Doors[1].AnticipatedOpen & (SafetySystems.DoorInterlockState == DoorInterlockStates.Right | SafetySystems.DoorInterlockState == DoorInterlockStates.Unlocked)) 72 { 73 Cars[i].Doors[1].AnticipatedOpen = false; 74 sr = true; 75 } 76 } 77 78 if (sl) 79 { 80 for (int i = 0; i < Cars.Length; i++) 81 { 82 Cars[i].Doors[0].CloseSound.Play(Cars[i].Specs.DoorClosePitch, 1.0, Cars[i], false); 83 } 84 } 85 86 if (sr) 87 { 88 for (int i = 0; i < Cars.Length; i++) 89 { 90 Cars[i].Doors[1].CloseSound.Play(Cars[i].Specs.DoorClosePitch, 1.0, Cars[i], false); 91 } 92 } 93 } 94 95 /// <summary>Returns the combination of door states encountered in a </summary> 96 /// <param name="Left">Whether to include left doors.</param> 97 /// <param name="Right">Whether to include right doors.</param> 98 /// <returns>A bit mask combining encountered door states.</returns> GetDoorsState(bool Left, bool Right)99 public TrainDoorState GetDoorsState(bool Left, bool Right) 100 { 101 bool opened = false, closed = false, mixed = false; 102 for (int i = 0; i < Cars.Length; i++) 103 { 104 for (int j = 0; j < Cars[i].Doors.Length; j++) 105 { 106 if (Left & Cars[i].Doors[j].Direction == -1 | Right & Cars[i].Doors[j].Direction == 1) 107 { 108 if (Cars[i].Doors[j].State == 0.0) 109 { 110 closed = true; 111 } 112 else if (Cars[i].Doors[j].State == 1.0) 113 { 114 opened = true; 115 } 116 else 117 { 118 mixed = true; 119 } 120 } 121 } 122 } 123 124 TrainDoorState Result = TrainDoorState.None; 125 if (opened) Result |= TrainDoorState.Opened; 126 if (closed) Result |= TrainDoorState.Closed; 127 if (mixed) Result |= TrainDoorState.Mixed; 128 if (opened & !closed & !mixed) Result |= TrainDoorState.AllOpened; 129 if (!opened & closed & !mixed) Result |= TrainDoorState.AllClosed; 130 if (!opened & !closed & mixed) Result |= TrainDoorState.AllMixed; 131 return Result; 132 } 133 134 /// <summary>Called once a frame for each train when arriving at a station, in order to update the automatic doors</summary> 135 /// <param name="NextStation">The train's next station</param> 136 /// <param name="BackwardsTolerance">The backwards tolerance for this stop point</param> 137 /// <param name="ForwardsTolerance">The forwards tolerance for this stop point</param> AttemptToOpenDoors(Station NextStation, double BackwardsTolerance, double ForwardsTolerance)138 public void AttemptToOpenDoors(Station NextStation, double BackwardsTolerance, double ForwardsTolerance) 139 { 140 if ((GetDoorsState(NextStation.OpenLeftDoors, NextStation.OpenRightDoors) & TrainDoorState.AllOpened) == 0) 141 { 142 if (StationDistanceToStopPoint < BackwardsTolerance & -StationDistanceToStopPoint < ForwardsTolerance) 143 { 144 OpenDoors(NextStation.OpenLeftDoors, NextStation.OpenRightDoors); 145 } 146 147 } 148 } 149 150 /// <summary>Called once a frame for each train whilst stopped at a station with the doors open, in order to update the automatic doors</summary> AttemptToCloseDoors()151 public void AttemptToCloseDoors() 152 { 153 if (TrainManagerBase.currentHost.InGameTime >= StationDepartureTime - 1.0 / Cars[DriverCar].Specs.DoorCloseFrequency) 154 { 155 if ((GetDoorsState(true, true) & TrainDoorState.AllClosed) == 0) 156 { 157 CloseDoors(true, true); 158 Specs.DoorClosureAttempted = true; 159 } 160 } 161 } 162 163 /// <summary>Is called once a frame, to update the door states of the train</summary> 164 /// <param name="TimeElapsed">The frame time elapsed</param> UpdateDoors(double TimeElapsed)165 public void UpdateDoors(double TimeElapsed) 166 { 167 DoorStates oldState = DoorStates.None; 168 DoorStates newState = DoorStates.None; 169 for (int i = 0; i < Cars.Length; i++) 170 { 171 bool ld = Cars[i].Doors[0].AnticipatedOpen; 172 bool rd = Cars[i].Doors[1].AnticipatedOpen; 173 double os = Cars[i].Specs.DoorOpenFrequency; 174 double cs = Cars[i].Specs.DoorCloseFrequency; 175 176 for (int j = 0; j < Cars[i].Doors.Length; j++) 177 { 178 if (Cars[i].Doors[j].Direction == -1 | Cars[i].Doors[j].Direction == 1) 179 { 180 bool shouldBeOpen = Cars[i].Doors[j].Direction == -1 ? ld : rd; 181 if (Cars[i].Doors[j].State > 0.0) 182 { 183 if (Cars[i].Doors[j].Direction == -1) 184 { 185 oldState |= DoorStates.Left; 186 } 187 else 188 { 189 oldState |= DoorStates.Right; 190 } 191 } 192 193 if (shouldBeOpen) 194 { 195 // open 196 Cars[i].Doors[j].State += os * TimeElapsed; 197 if (Cars[i].Doors[j].State > 1.0) 198 { 199 Cars[i].Doors[j].State = 1.0; 200 } 201 } 202 else 203 { 204 // close 205 if (Cars[i].Doors[j].DoorLockDuration > 0.0) 206 { 207 if (Cars[i].Doors[j].State > Cars[i].Doors[j].DoorLockState) 208 { 209 Cars[i].Doors[j].State -= cs * TimeElapsed; 210 } 211 212 if (Cars[i].Doors[j].State < Cars[i].Doors[j].DoorLockState) 213 { 214 Cars[i].Doors[j].State = Cars[i].Doors[j].DoorLockState; 215 } 216 217 Cars[i].Doors[j].DoorLockDuration -= TimeElapsed; 218 if (Cars[i].Doors[j].DoorLockDuration < 0.0) 219 { 220 Cars[i].Doors[j].DoorLockDuration = 0.0; 221 } 222 } 223 else 224 { 225 Cars[i].Doors[j].State -= cs * TimeElapsed; 226 } 227 228 if (Cars[i].Doors[j].AnticipatedReopen && Cars[i].Doors[j].State < Cars[i].Doors[j].InterferingObjectRate) 229 { 230 Cars[i].Doors[j].State = Cars[i].Doors[j].InterferingObjectRate; 231 } 232 233 if (Cars[i].Doors[j].State < 0.0) 234 { 235 Cars[i].Doors[j].State = 0.0; 236 } 237 } 238 239 if (Cars[i].Doors[j].State > 0.0) 240 { 241 if (Cars[i].Doors[j].Direction == -1) 242 { 243 newState |= DoorStates.Left; 244 } 245 else 246 { 247 newState |= DoorStates.Right; 248 } 249 } 250 } 251 } 252 } 253 254 if (SafetySystems.PilotLamp != null) 255 { 256 SafetySystems.PilotLamp.Update(newState); 257 } 258 259 if (oldState != newState) 260 { 261 if (Plugin != null) 262 { 263 Plugin.DoorChange(oldState, newState); 264 } 265 for (int j = 0; j < InputDevicePlugin.AvailablePluginInfos.Count; j++) 266 { 267 if (InputDevicePlugin.AvailablePluginInfos[j].Status == InputDevicePlugin.PluginInfo.PluginStatus.Enable && InputDevicePlugin.AvailablePlugins[j] is ITrainInputDevice) 268 { 269 ITrainInputDevice trainInputDevice = (ITrainInputDevice)InputDevicePlugin.AvailablePlugins[j]; 270 trainInputDevice.DoorChange(oldState, newState); 271 } 272 } 273 } 274 } 275 } 276 } 277