1 using System;
2 using OpenBveApi.Math;
3 using TrainManager.Handles;
4 using TrainManager.Trains;
5 
6 // ReSharper disable UnusedMember.Global
7 
8 namespace OpenBve
9 {
10     /// <summary>This is a proxy class, which provides read-only access to variables, in a manner analagous to that found in .animated files </summary>
11     /// Notes:
12     /// A proxy class is required, as otherwise we start making a horrendous amount of stuff public which shouldn't be, when working with cross-assembly access.
13     /// Doing it this way, also allows for sensible scripting access, rather than climbing through multiple levels.
14     public static class Scripting
15     {
16         /// <summary>
17         /// Provides scripting access to signals
18         /// </summary>
19         public static class Signal
20         {
21             /// <summary>This method returns the current aspect of the selected section</summary>
22             /// <param name="Train">The train for which we wish to get the section index</param>
23             /// <param name="SectionIndex">The section to get the aspect for</param>
24             /// <param name="IsPartOfTrain">Defines whether we wish to get the section index for the selected train, or for when placed via a .SigF command</param>
25             /// <returns>The aspect of the selected signal</returns>
CurrentAspect(TrainBase Train, int SectionIndex, bool IsPartOfTrain)26             public static int CurrentAspect(TrainBase Train, int SectionIndex, bool IsPartOfTrain)
27             {
28                 if (IsPartOfTrain)
29                 {
30                     int nextSectionIndex = Train.CurrentSectionIndex + 1;
31                     if (nextSectionIndex >= 0 & nextSectionIndex < Program.CurrentRoute.Sections.Length)
32                     {
33                         int a = Program.CurrentRoute.Sections[nextSectionIndex].CurrentAspect;
34                         if (a >= 0 & a < Program.CurrentRoute.Sections[nextSectionIndex].Aspects.Length)
35                         {
36                             return Program.CurrentRoute.Sections[nextSectionIndex].Aspects[a].Number;
37                         }
38                         return 0;
39                     }
40                 }
41                 else if (SectionIndex >= 0 & SectionIndex < Program.CurrentRoute.Sections.Length)
42                 {
43                     int a = Program.CurrentRoute.Sections[SectionIndex].CurrentAspect;
44                     if (a >= 0 & a < Program.CurrentRoute.Sections[SectionIndex].Aspects.Length)
45                     {
46                         return Program.CurrentRoute.Sections[SectionIndex].Aspects[a].Number;
47                     }
48                 }
49                 return 0;
50             }
51         }
52 
53         /// <summary>
54         /// Provides scripting access to trains internal variables
55         /// </summary>
56         public static class Train
57         {
58             /// <summary>Returns the number of cars in this train</summary>
59             /// <param name="Train">The selected train</param>
60             /// <returns>The number of cars</returns>
numberOfCars(TrainBase Train)61             public static int numberOfCars(TrainBase Train)
62             {
63                 if (Train != null)
64                 {
65                     return Train.Cars.Length;
66                 }
67                 return 0;
68             }
69 
70             /// <summary>Returns the speed of the selected car </summary>
71             /// <param name="Train">The selected train</param>
72             /// <param name="CarIndex">The car for which to get the speed</param>
73             /// <returns>The speed in m/s</returns>
speed(TrainBase Train, int CarIndex)74             public static double speed(TrainBase Train, int CarIndex)
75             {
76                 if (Train == null)
77                 {
78                     return 0;
79                 }
80                 if (CarIndex > Train.Cars.Length)
81                 {
82                     return Train.Cars[0].CurrentSpeed;
83                 }
84                 return Train.Cars[CarIndex].CurrentSpeed;
85             }
86 
87             /// <summary>Returns the speed of the selected car, accounting for wheelslip and wheel lock</summary>
88             /// <param name="Train">The selected train</param>
89             /// <param name="CarIndex">The car for which to get the speed</param>
90             /// <returns>The speed in m/s</returns>
speedometer(TrainBase Train, int CarIndex)91             public static double speedometer(TrainBase Train, int CarIndex)
92             {
93                 if (Train == null)
94                 {
95                     return 0;
96                 }
97                 return CarIndex > Train.Cars.Length
98                     ? Train.Cars[0].Specs.PerceivedSpeed
99                     : Train.Cars[CarIndex].Specs.PerceivedSpeed;
100             }
101 
102             /// <summary>Returns the acceleration of the selected car</summary>
103             /// <param name="Train">The selected train</param>
104             /// <param name="CarIndex">The car for which to get the acceleration</param>
105             /// <returns>The acceleration in m/s</returns>
acceleration(TrainBase Train, int CarIndex)106             public static double acceleration(TrainBase Train, int CarIndex)
107             {
108                 if (Train == null)
109                 {
110                     return 0;
111                 }
112                 return CarIndex > Train.Cars.Length
113                     ? Train.Cars[0].Specs.Acceleration
114                     : Train.Cars[CarIndex].Specs.Acceleration;
115             }
116 
117             /// <summary>Returns the acceleration that the first motor car is currently generating in m/s</summary>
118             /// <param name="Train">The selected train</param>
119             /// <returns>The acceleration in m/s</returns>
accelerationMotor(TrainBase Train)120             public static double accelerationMotor(TrainBase Train)
121             {
122                 if (Train == null) return 0.0;
123                 for (int j = 0; j < Train.Cars.Length; j++)
124                 {
125                     if (Train.Cars[j].Specs.IsMotorCar)
126                     {
127                         // hack: MotorAcceleration does not distinguish between forward/backward
128                         if (Train.Cars[j].Specs.MotorAcceleration < 0.0)
129                         {
130                             return Train.Cars[j].Specs.MotorAcceleration*
131                                    (double) Math.Sign(Train.Cars[j].CurrentSpeed);
132                         }
133                         if (Train.Cars[j].Specs.MotorAcceleration > 0.0)
134                         {
135                             return Train.Cars[j].Specs.MotorAcceleration*
136                                    (double) Train.Handles.Reverser.Actual;
137                         }
138                     }
139                 }
140                 return 0.0;
141             }
142 
143             /// <summary>Returns the acceleration that the selected car's motor is currently generating in m/s</summary>
144             /// <param name="Train">The selected train</param>
145             /// <param name="CarIndex">The selected car</param>
146             /// <returns>The acceleration in m/s</returns>
accelerationMotor(TrainBase Train, int CarIndex)147             public static double accelerationMotor(TrainBase Train, int CarIndex)
148             {
149                 if (Train == null || Train.Cars.Length <= CarIndex) return 0.0;
150                 if (Train.Cars[CarIndex].Specs.IsMotorCar)
151                 {
152                     // hack: MotorAcceleration does not distinguish between forward/backward
153                     if (Train.Cars[CarIndex].Specs.MotorAcceleration < 0.0)
154                     {
155                         return Train.Cars[CarIndex].Specs.MotorAcceleration*
156                                (double) Math.Sign(Train.Cars[CarIndex].CurrentSpeed);
157                     }
158                     if (Train.Cars[CarIndex].Specs.MotorAcceleration > 0.0)
159                     {
160                         return Train.Cars[CarIndex].Specs.MotorAcceleration*
161                                (double) Train.Handles.Reverser.Actual;
162                     }
163                 }
164                 return 0.0;
165             }
166 
167             /// <summary>Returns the cartesian distance to the nearest car of the selected train</summary>
168             /// <param name="Train">The selected train</param>
169             /// <param name="Position">The object's absolute in-game position</param>
170             /// <returns>The distance to the object</returns>
distance(TrainBase Train, Vector3 Position)171             public static double distance(TrainBase Train, Vector3 Position)
172             {
173                 if (Train == null) return 0.0;
174                 double dist = double.MaxValue;
175                 for (int j = 0; j < Train.Cars.Length; j++)
176                 {
177                     double fx = Train.Cars[j].FrontAxle.Follower.WorldPosition.X - Position.X;
178                     double fy = Train.Cars[j].FrontAxle.Follower.WorldPosition.Y - Position.Y;
179                     double fz = Train.Cars[j].FrontAxle.Follower.WorldPosition.Z - Position.Z;
180                     double f = fx*fx + fy*fy + fz*fz;
181                     if (f < dist) dist = f;
182                     double rx = Train.Cars[j].RearAxle.Follower.WorldPosition.X - Position.X;
183                     double ry = Train.Cars[j].RearAxle.Follower.WorldPosition.Y - Position.Y;
184                     double rz = Train.Cars[j].RearAxle.Follower.WorldPosition.Z - Position.Z;
185                     double r = rx*rx + ry*ry + rz*rz;
186                     if (r < dist) dist = r;
187                 }
188                 return Math.Sqrt(dist);
189             }
190 
191             /// <summary>Returns the cartesian distance to the selected car of the selected train</summary>
192             /// <param name="Train">The selected train</param>
193             /// <param name="CarIndex">The selected car</param>
194             /// <param name="Position">The object's absolute in-game position</param>
195             /// <returns>The distance to the object</returns>
distance(TrainBase Train, int CarIndex, Vector3 Position)196             public static double distance(TrainBase Train, int CarIndex, Vector3 Position)
197             {
198                 if (Train == null || Train.Cars.Length <= CarIndex) return 0.0;
199                 double x = 0.5*
200                            (Train.Cars[CarIndex].FrontAxle.Follower.WorldPosition.X +
201                             Train.Cars[CarIndex].RearAxle.Follower.WorldPosition.X) - Position.X;
202                 double y = 0.5*
203                            (Train.Cars[CarIndex].FrontAxle.Follower.WorldPosition.Y +
204                             Train.Cars[CarIndex].RearAxle.Follower.WorldPosition.Y) - Position.Y;
205                 double z = 0.5*
206                            (Train.Cars[CarIndex].FrontAxle.Follower.WorldPosition.Z +
207                             Train.Cars[CarIndex].RearAxle.Follower.WorldPosition.Z) - Position.Z;
208                 return Math.Sqrt(x*x + y*y + z*z);
209             }
210 
211             /// <summary>Returns the track distance to the nearest car of the selected train</summary>
212             /// <param name="Train">The selected train</param>
213             /// <param name="TrackPosition">The object's track position</param>
214             /// <returns>The distance to the object</returns>
trackDistance(TrainBase Train, double TrackPosition)215             public static double trackDistance(TrainBase Train, double TrackPosition)
216             {
217                 if (Train == null) return 0.0;
218                 double t0 = Train.FrontCarTrackPosition();
219                 double t1 = Train.RearCarTrackPosition();
220                 return TrackPosition > t0 ? TrackPosition - t0 : TrackPosition < t1 ? TrackPosition - t1 : 0.0;
221             }
222 
223             /// <summary>Returns the track distance to the nearest car of the selected train</summary>
224             /// <param name="Train">The selected train</param>
225             /// <param name="CarIndex">The selected car</param>
226             /// <param name="TrackPosition">The object's track position</param>
227             /// <returns>The distance to the object</returns>
trackDistance(TrainBase Train, int CarIndex, double TrackPosition)228             public static double trackDistance(TrainBase Train, int CarIndex, double TrackPosition)
229             {
230                 if (Train == null) return 0.0;
231                 if (Train.Cars.Length > CarIndex)
232                 {
233                     CarIndex = Train.Cars.Length - 1;
234                 }
235                 double t1 = Train.Cars[CarIndex].RearAxle.Follower.TrackPosition - Train.Cars[CarIndex].RearAxle.Position -
236                             0.5*Train.Cars[CarIndex].Length;
237                 return TrackPosition < t1 ? TrackPosition - t1 : 0.0;
238             }
239 
240             /// <summary>Returns the main brake reservoir pressure of the selected car of the selected train</summary>
241             /// <param name="Train">The selected train</param>
242             /// <param name="CarIndex">The selected car</param>
243             /// <returns>The main brake reservoir pressure in Pa</returns>
mainReservoir(TrainBase Train, int CarIndex)244             public static double mainReservoir(TrainBase Train, int CarIndex)
245             {
246                 if (Train == null) return 0.0;
247                 if (Train.Cars.Length > CarIndex)
248                 {
249                     return 0.0;
250                 }
251                 return Train.Cars[CarIndex].CarBrake.mainReservoir.CurrentPressure;
252             }
253 
254             /// <summary>Returns the brake pipe pressure of the selected car of the selected train</summary>
255             /// <param name="Train">The selected train</param>
256             /// <param name="CarIndex">The selected car</param>
257             /// <returns>The brake pipe pressure in Pa</returns>
brakePipe(TrainBase Train, int CarIndex)258             public static double brakePipe(TrainBase Train, int CarIndex)
259             {
260                 if (Train == null) return 0.0;
261                 if (Train.Cars.Length > CarIndex)
262                 {
263                     return 0.0;
264                 }
265                 return Train.Cars[CarIndex].CarBrake.brakePipe.CurrentPressure;
266             }
267 
268             /// <summary>Returns the brake cylinder pressure of the selected car of the selected train</summary>
269             /// <param name="Train">The selected train</param>
270             /// <param name="CarIndex">The selected car</param>
271             /// <returns>The brake cylinder pressure in Pa</returns>
brakeCylinder(TrainBase Train, int CarIndex)272             public static double brakeCylinder(TrainBase Train, int CarIndex)
273             {
274                 if (Train == null) return 0.0;
275                 if (Train.Cars.Length > CarIndex)
276                 {
277                     return 0.0;
278                 }
279                 return Train.Cars[CarIndex].CarBrake.brakeCylinder.CurrentPressure;
280             }
281 
282             /// <summary>Returns the brake pipe pressure of the selected car of the selected train</summary>
283             /// <param name="Train">The selected train</param>
284             /// <param name="CarIndex">The selected car</param>
285             /// <returns>The brake pipe pressure in Pa</returns>
straightAirPipe(TrainBase Train, int CarIndex)286             public static double straightAirPipe(TrainBase Train, int CarIndex)
287             {
288                 if (Train == null) return 0.0;
289                 if (Train.Cars.Length > CarIndex)
290                 {
291                     return 0.0;
292                 }
293                 return Train.Cars[CarIndex].CarBrake.straightAirPipe.CurrentPressure;
294             }
295 
296             /// <summary>Returns the doors state of the selected train</summary>
297             /// <param name="Train">The selected train</param>
298             /// <returns>0.0 if all doors are closed, 1.0 if all doors are open, or a value in between</returns>
doors(TrainBase Train)299             public static double doors(TrainBase Train)
300             {
301                 if (Train == null) return 0.0;
302                 double doorsState = 0.0;
303                 for (int j = 0; j < Train.Cars.Length; j++)
304                 {
305                     for (int k = 0; k < Train.Cars[j].Doors.Length; k++)
306                     {
307                         if (Train.Cars[j].Doors[k].State > doorsState)
308                         {
309                             doorsState = Train.Cars[j].Doors[k].State;
310                         }
311                     }
312                 }
313                 return doorsState;
314             }
315 
316             /// <summary>Returns the doors state of the selected car of the selected train</summary>
317             /// <param name="Train">The selected train</param>
318             /// <param name="CarIndex">The selected car</param>
319             /// <returns>0.0 if all doors are closed, 1.0 if all doors are open, or a value in between</returns>
doors(TrainBase Train, int CarIndex)320             public static double doors(TrainBase Train, int CarIndex)
321             {
322                 if (Train == null) return 0.0;
323                 if (Train.Cars.Length <= CarIndex)
324                 {
325                     double doorsState = 0.0;
326                     for (int k = 0; k < Train.Cars[CarIndex].Doors.Length; k++)
327                     {
328                         if (Train.Cars[CarIndex].Doors[k].State > doorsState)
329                         {
330                             doorsState = Train.Cars[CarIndex].Doors[k].State;
331                         }
332                     }
333                     return doorsState;
334                 }
335                 return 0.0;
336             }
337 
338             /// <summary>Returns the left-hand doors state of the selected train</summary>
339             /// <param name="Train">The selected train</param>
340             /// <returns>0.0 if all doors are closed, 1.0 if all doors are open, or a value in between</returns>
leftDoors(TrainBase Train)341             public static double leftDoors(TrainBase Train)
342             {
343                 if (Train == null) return 0.0;
344                 double doorsState = 0.0;
345                 for (int j = 0; j < Train.Cars.Length; j++)
346                 {
347                     for (int k = 0; k < Train.Cars[j].Doors.Length; k++)
348                     {
349                         if (Train.Cars[j].Doors[k].Direction == -1 &
350                             Train.Cars[j].Doors[k].State > doorsState)
351                         {
352                             doorsState = Train.Cars[j].Doors[k].State;
353                         }
354                     }
355                 }
356                 return doorsState;
357             }
358 
359             /// <summary>Returns the left-hand doors state of the selected car of the selected train</summary>
360             /// <param name="Train">The selected train</param>
361             /// <param name="CarIndex">The selected car</param>
362             /// <returns>0.0 if all doors are closed, 1.0 if all doors are open, or a value in between</returns>
leftDoors(TrainBase Train, int CarIndex)363             public static double leftDoors(TrainBase Train, int CarIndex)
364             {
365                 if (Train == null) return 0.0;
366                 if (Train.Cars.Length <= CarIndex)
367                 {
368                     double doorsState = 0.0;
369                     for (int k = 0; k < Train.Cars[CarIndex].Doors.Length; k++)
370                     {
371                         if (Train.Cars[CarIndex].Doors[k].Direction == -1 &
372                             Train.Cars[CarIndex].Doors[k].State > doorsState)
373                         {
374                             doorsState = Train.Cars[CarIndex].Doors[k].State;
375                         }
376                     }
377                     return doorsState;
378                 }
379                 return 0.0;
380             }
381 
382             /// <summary>Returns the left-hand doors state of the selected train</summary>
383             /// <param name="Train">The selected train</param>
384             /// <returns>0.0 if all doors are closed, 1.0 if all doors are open, or a value in between</returns>
rightDoors(TrainBase Train)385             public static double rightDoors(TrainBase Train)
386             {
387                 if (Train == null) return 0.0;
388                 double doorsState = 0.0;
389                 for (int j = 0; j < Train.Cars.Length; j++)
390                 {
391                     for (int k = 0; k < Train.Cars[j].Doors.Length; k++)
392                     {
393                         if (Train.Cars[j].Doors[k].Direction == 1 &
394                             Train.Cars[j].Doors[k].State > doorsState)
395                         {
396                             doorsState = Train.Cars[j].Doors[k].State;
397                         }
398                     }
399                 }
400                 return doorsState;
401             }
402 
403             /// <summary>Returns the left-hand doors state of the selected car of the selected train</summary>
404             /// <param name="Train">The selected train</param>
405             /// <param name="CarIndex">The selected car</param>
406             /// <returns>0.0 if all doors are closed, 1.0 if all doors are open, or a value in between</returns>
rightDoors(TrainBase Train, int CarIndex)407             public static double rightDoors(TrainBase Train, int CarIndex)
408             {
409                 if (Train == null) return 0.0;
410                 if (Train.Cars.Length <= CarIndex)
411                 {
412                     double doorsState = 0.0;
413                     for (int k = 0; k < Train.Cars[CarIndex].Doors.Length; k++)
414                     {
415                         if (Train.Cars[CarIndex].Doors[k].Direction == 1 &
416                             Train.Cars[CarIndex].Doors[k].State > doorsState)
417                         {
418                             doorsState = Train.Cars[CarIndex].Doors[k].State;
419                         }
420                     }
421                     return doorsState;
422                 }
423                 return 0.0;
424             }
425 
426             /// <summary>Returns whether the left doors are opening for the selected train</summary>
427             /// <param name="Train">The selected train</param>
428             /// <returns>True if the doors are opening, false otherwise</returns>
leftDoorsTarget(TrainBase Train)429             public static bool leftDoorsTarget(TrainBase Train)
430             {
431                 if (Train == null) return false;
432                 for (int j = 0; j < Train.Cars.Length; j++)
433                 {
434                     for (int k = 0; k < Train.Cars.Length; k++)
435                     {
436                         if (Train.Cars[j].Doors[0].AnticipatedOpen)
437                         {
438                             return true;
439                         }
440                     }
441                 }
442                 return false;
443             }
444 
445             /// <summary>Returns whether the left doors are opening for the selected car of the selected train</summary>
446             /// <param name="Train">The selected train</param>
447             /// <param name="CarIndex">The selected car</param>
448             /// <returns>True if the doors are opening, false otherwise</returns>
leftDoorsTarget(TrainBase Train, int CarIndex)449             public static bool leftDoorsTarget(TrainBase Train, int CarIndex)
450             {
451                 if (Train == null) return false;
452                 if (Train.Cars.Length <= CarIndex)
453                 {
454                     if (Train.Cars[CarIndex].Doors[0].AnticipatedOpen)
455                     {
456                         return true;
457                     }
458 
459                 }
460                 return false;
461             }
462 
463             /// <summary>Returns whether the left doors are opening for the selected train</summary>
464             /// <param name="Train">The selected train</param>
465             /// <returns>True if the doors are opening, false otherwise</returns>
rightDoorsTarget(TrainBase Train)466             public static bool rightDoorsTarget(TrainBase Train)
467             {
468                 if (Train == null) return false;
469                 for (int j = 0; j < Train.Cars.Length; j++)
470                 {
471                     for (int k = 0; k < Train.Cars.Length; k++)
472                     {
473                         if (Train.Cars[j].Doors[1].AnticipatedOpen)
474                         {
475                             return true;
476                         }
477                     }
478                 }
479                 return false;
480             }
481 
482             /// <summary>Returns whether the left doors are opening for the selected car of the selected train</summary>
483             /// <param name="Train">The selected train</param>
484             /// <param name="CarIndex">The selected car</param>
485             /// <returns>True if the doors are opening, false otherwise</returns>
rightDoorsTarget(TrainBase Train, int CarIndex)486             public static bool rightDoorsTarget(TrainBase Train, int CarIndex)
487             {
488                 if (Train == null) return false;
489                 if (Train.Cars.Length <= CarIndex)
490                 {
491                     if (Train.Cars[CarIndex].Doors[1].AnticipatedOpen)
492                     {
493                         return true;
494                     }
495 
496                 }
497                 return false;
498             }
499 
500             /// <summary>Returns the driver's selected reverser position for the selected train</summary>
501             /// <param name="Train">The selected train</param>
502             /// <returns>-1 for backwards, 0 for neutral, 1 for forwards</returns>
reverserNotch(TrainBase Train)503             public static int reverserNotch(TrainBase Train)
504             {
505                 if (Train == null) return 0;
506                 return (int)Train.Handles.Reverser.Driver;
507             }
508 
509             /// <summary>Returns the driver's selected power notch for the selected train</summary>
510             /// <param name="Train">The selected train</param>
511             /// <returns>The driver's selected power notch</returns>
powerNotch(TrainBase Train)512             public static int powerNotch(TrainBase Train)
513             {
514                 if (Train == null) return 0;
515                 return Train.Handles.Power.Driver;
516             }
517 
518             /// <summary>Returns the maximum power notch for the selected train</summary>
519             /// <param name="Train">The selected train</param>
520             /// <returns>The maximum power notch</returns>
powerNotches(TrainBase Train)521             public static int powerNotches(TrainBase Train)
522             {
523                 if (Train == null) return 0;
524                 return Train.Handles.Power.MaximumNotch;
525             }
526 
527             /// <summary>Returns the driver's selected brake notch for the selected train</summary>
528             /// <param name="Train">The selected train</param>
529             /// <returns>The driver's selected power notch</returns>
brakeNotch(TrainBase Train)530             public static int brakeNotch(TrainBase Train)
531             {
532                 if (Train == null) return 0;
533                 return Train.Handles.Brake.Driver;
534             }
535 
536             /// <summary>Returns the maximum brake notch for the selected train</summary>
537             /// <param name="Train">The selected train</param>
538             /// <returns>The maximum power notch</returns>
brakeNotches(TrainBase Train)539             public static int brakeNotches(TrainBase Train)
540             {
541                 if (Train == null) return 0;
542                 return Train.Handles.Brake.MaximumNotch;
543             }
544 
545             /// <summary>Returns the driver's selected brake notch (Including EB) for the selected train</summary>
546             /// <param name="Train">The selected train</param>
547             /// <returns>The driver's selected brake notch</returns>
brakeNotchLinear(TrainBase Train)548             public static int brakeNotchLinear(TrainBase Train)
549             {
550                 if (Train == null) return 0;
551                 if (Train.Handles.Brake is AirBrakeHandle)
552                 {
553                     if (Train.Handles.EmergencyBrake.Driver)
554                     {
555                         return 3;
556                     }
557                     return (int) Train.Handles.Brake.Driver;
558                 }
559                 if (Train.Handles.HasHoldBrake)
560                 {
561                     if (Train.Handles.EmergencyBrake.Driver)
562                     {
563                         return (int) Train.Handles.Brake.MaximumNotch + 2;
564                     }
565                     if (Train.Handles.Brake.Driver > 0)
566                     {
567                         return (int) Train.Handles.Brake.Driver + 1;
568                     }
569                     return Train.Handles.HoldBrake.Driver ? 1 : 0;
570                 }
571                 if (Train.Handles.EmergencyBrake.Driver)
572                 {
573                     return (int) Train.Handles.Brake.MaximumNotch + 1;
574                 }
575                 return (int) Train.Handles.Brake.Driver;
576             }
577 
578             /// <summary>Returns the maximum possible brake notch (Including EB) for the selected train</summary>
579             /// <param name="Train">The selected train</param>
580             /// <returns>The maximum possible brake notch</returns>
brakeNotchesLinear(TrainBase Train)581             public static int brakeNotchesLinear(TrainBase Train)
582             {
583                 if (Train == null) return 0;
584                 if (Train.Handles.Brake is AirBrakeHandle)
585                 {
586                     return 3;
587                 }
588                 if (Train.Handles.HasHoldBrake)
589                 {
590                     return 2;
591                 }
592                 return Train.Handles.Brake.MaximumNotch + 1;
593             }
594 
595             /// <summary>Returns whether EB is active for the selected train</summary>
596             /// <param name="Train">The selected train</param>
597             /// <returns>Whether EB is active</returns>
emergencyBrake(TrainBase Train)598             public static bool emergencyBrake(TrainBase Train)
599             {
600                 if (Train == null) return false;
601                 return Train.Handles.EmergencyBrake.Driver;
602             }
603 
604             /// <summary>Whether the selected train has an automatic air brake</summary>
605             /// <param name="Train">The selected train</param>
606             /// <returns>Whether the selected train has an automatic air brake</returns>
hasAirBrake(TrainBase Train)607             public static bool hasAirBrake(TrainBase Train)
608             {
609                 if (Train == null) return false;
610                 return Train.Handles.Brake is AirBrakeHandle;
611             }
612 
613             /// <summary>Whether the hold brake is currently active for the selected train</summary>
614             /// <param name="Train">The selected train</param>
615             /// <returns>Whether the hold brake is currently active</returns>
holdBrake(TrainBase Train)616             public static bool holdBrake(TrainBase Train)
617             {
618                 if (Train == null) return false;
619                 return Train.Handles.HoldBrake.Driver;
620             }
621 
622             /// <summary>Whether the selected train has a hold brake</summary>
623             /// <param name="Train">The selected train</param>
624             /// <returns>Whether the selected train has a hold brake</returns>
hasHoldBrake(TrainBase Train)625             public static bool hasHoldBrake(TrainBase Train)
626             {
627                 if (Train == null) return false;
628                 return Train.Handles.HasHoldBrake;
629             }
630 
631             /// <summary>Whether the constant speed devicee is currently active for the selected train</summary>
632             /// <param name="Train">The selected train</param>
633             /// <returns>Whether the constant speed device is currently active</returns>
constantSpeed(TrainBase Train)634             public static bool constantSpeed(TrainBase Train)
635             {
636                 if (Train == null) return false;
637                 return Train.Specs.CurrentConstSpeed;
638             }
639 
640             /// <summary>Whether the selected train has a constant speed device</summary>
641             /// <param name="Train">The selected train</param>
642             /// <returns>Whether the selected train has a constant speed device</returns>
hasConstantSpeed(TrainBase Train)643             public static bool hasConstantSpeed(TrainBase Train)
644             {
645                 if (Train == null) return false;
646                 return Train.Specs.HasConstSpeed;
647             }
648 
649             /// <summary>Whether the selected train uses a custom plugin</summary>
650             /// <param name="Train">The selected train</param>
651             /// <returns>True if the train uses a custom plugin, false otherwise</returns>
hasPlugin(TrainBase Train)652             public static bool hasPlugin(TrainBase Train)
653             {
654                 if (Train == null) return false;
655                 if (Train.IsPlayerTrain && Train.Plugin != null)
656                 {
657                     return TrainManager.PlayerTrain.Plugin.IsDefault;
658                 }
659                 return false;
660             }
661 
662             /// <summary>Whether the selected train has a hold brake</summary>
663             /// <param name="Train">The selected train</param>
664             /// <param name="pluginState">The plugin state to query</param>
665             /// <returns>The plugin state value</returns>
pluginState(TrainBase Train, int pluginState)666             public static int pluginState(TrainBase Train, int pluginState)
667             {
668                 if (Train == null || Train.Plugin == null)
669                 {
670                     return 0;
671                 }
672 
673                 if (pluginState >= 0 & pluginState < Train.Plugin.Panel.Length)
674                 {
675                     return Train.Plugin.Panel[pluginState];
676                 }
677                 return 0;
678             }
679         }
680 
681         /// <summary>
682         /// Provides scripting access to in simulation variables
683         /// </summary>
684         public static class Simulation
685         {
686             /// <summary>
687             /// Gets the current in-simulation time
688             /// </summary>
689             /// <returns>Returns the number of seconds elapsed since midnight on the first day</returns>
time()690             public static double time()
691             {
692                 return Program.CurrentRoute.SecondsSinceMidnight;
693             }
694 
695             /// <summary>Gets the camera distance in meters from the current object </summary>
696             /// <param name="Position">The absolute in-game position of the current object to test against</param>
697             /// <returns>The distance in meters</returns>
CameraDistance(Vector3 Position)698             public static double CameraDistance(Vector3 Position)
699             {
700                 double dx = Program.Renderer.Camera.AbsolutePosition.X - Position.X;
701                 double dy = Program.Renderer.Camera.AbsolutePosition.Y - Position.Y;
702                 double dz = Program.Renderer.Camera.AbsolutePosition.Z - Position.Z;
703                 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
704             }
705         }
706     }
707 }
708