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