示例#1
0
        public Triggers(STFReader stf)
        {
            stf.MustMatch("(");
            int count = stf.ReadInt(null);

            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("dist_travelled_trigger", () => { Add(new Dist_Travelled_Trigger(stf)); }),
                new STFReader.TokenProcessor("discrete_trigger", () => { Add(new Discrete_Trigger(stf)); }),
                new STFReader.TokenProcessor("random_trigger", () => { Add(new Random_Trigger(stf)); }),
                new STFReader.TokenProcessor("variable_trigger", () => { Add(new Variable_Trigger(stf)); }),
                new STFReader.TokenProcessor("initial_trigger", () => { Add(new Initial_Trigger(stf)); }),
            });
            foreach (Trigger trigger in this)
            {
                if (trigger.SoundCommand == null)
                {
                    STFException.TraceWarning(stf, "Trigger lacks a sound command");
                }
            }
        }
示例#2
0
        static IList <SignalDrawLight> ReadDrawLights(STFReader stf)
        {
            stf.MustMatch("(");
            int count = stf.ReadInt(null);
            List <SignalDrawLight> drawLights = new List <SignalDrawLight>(count);

            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("drawlight", () => {
                    if (drawLights.Count >= drawLights.Capacity)
                    {
                        STFException.TraceWarning(stf, "Skipped extra DrawLight");
                    }
                    else
                    {
                        drawLights.Add(new SignalDrawLight(stf));
                    }
                }),
            });
            return(drawLights);
        }
示例#3
0
        public Traffic_Service_Definition(STFReader stf)
        {
            var arrivalTime      = 0;
            var departTime       = 0;
            var skipCount        = 0;
            var distanceDownPath = 0F;
            var platformStartID  = 0;

            stf.MustMatch("(");
            Service_Definition = stf.ReadString();
            Time = stf.ReadInt(null);   // Cannot use stt.ReadFloat(STFReader.UNITS.Time, null) as number will be followed by "arrivaltime"
            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("arrivaltime", () => { arrivalTime = (int)stf.ReadFloatBlock(STFReader.UNITS.Time, null); }),
                new STFReader.TokenProcessor("departtime", () => { departTime = (int)stf.ReadFloatBlock(STFReader.UNITS.Time, null); }),
                new STFReader.TokenProcessor("skipcount", () => { skipCount = stf.ReadIntBlock(null); }),
                new STFReader.TokenProcessor("distancedownpath", () => { distanceDownPath = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }),
                new STFReader.TokenProcessor("platformstartid", () => { platformStartID = stf.ReadIntBlock(null);
                                                                        TrafficDetails.Add(new Traffic_Traffic_Item(arrivalTime, departTime, skipCount, distanceDownPath, platformStartID)); }),
            });
        }
示例#4
0
        internal ServiceTraffics(STFReader stf)
        {
            int   arrivalTime      = 0;
            int   departTime       = 0;
            int   skipCount        = 0;
            float distanceDownPath = 0f;
            int   platformStartID  = 0;

            stf.MustMatchBlockStart();
            Name = stf.ReadString();
            Time = stf.ReadInt(null);   // Cannot use stt.ReadFloat(STFReader.Units.Time, null) as number will be followed by "arrivaltime"
            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("arrivaltime", () => { arrivalTime = (int)stf.ReadFloatBlock(STFReader.Units.Time, null); }),
                new STFReader.TokenProcessor("departtime", () => { departTime = (int)stf.ReadFloatBlock(STFReader.Units.Time, null); }),
                new STFReader.TokenProcessor("skipcount", () => { skipCount = stf.ReadIntBlock(null); }),
                new STFReader.TokenProcessor("distancedownpath", () => { distanceDownPath = stf.ReadFloatBlock(STFReader.Units.Distance, null); }),
                new STFReader.TokenProcessor("platformstartid", () => { platformStartID = stf.ReadIntBlock(null);
                                                                        Add(new ServiceTrafficItem(arrivalTime, departTime, skipCount, distanceDownPath, platformStartID, this)); }),
            });
        }
示例#5
0
 public Light(int index, STFReader stf)
 {
     Index = index;
     stf.MustMatch("(");
     stf.ParseBlock(new[] {
         new STFReader.TokenProcessor("type", () => { Type = (LightType)stf.ReadIntBlock(null); }),
         new STFReader.TokenProcessor("conditions", () => { stf.MustMatch("("); stf.ParseBlock(new[] {
                 new STFReader.TokenProcessor("headlight", () => { Headlight = (LightHeadlightCondition)stf.ReadIntBlock(null); }),
                 new STFReader.TokenProcessor("unit", () => { Unit = (LightUnitCondition)stf.ReadIntBlock(null); }),
                 new STFReader.TokenProcessor("penalty", () => { Penalty = (LightPenaltyCondition)stf.ReadIntBlock(null); }),
                 new STFReader.TokenProcessor("control", () => { Control = (LightControlCondition)stf.ReadIntBlock(null); }),
                 new STFReader.TokenProcessor("service", () => { Service = (LightServiceCondition)stf.ReadIntBlock(null); }),
                 new STFReader.TokenProcessor("timeofday", () => { TimeOfDay = (LightTimeOfDayCondition)stf.ReadIntBlock(null); }),
                 new STFReader.TokenProcessor("weather", () => { Weather = (LightWeatherCondition)stf.ReadIntBlock(null); }),
                 new STFReader.TokenProcessor("coupling", () => { Coupling = (LightCouplingCondition)stf.ReadIntBlock(null); }),
             }); }),
         new STFReader.TokenProcessor("cycle", () => { Cycle = 0 != stf.ReadIntBlock(null); }),
         new STFReader.TokenProcessor("fadein", () => { FadeIn = stf.ReadFloatBlock(STFReader.UNITS.None, null); }),
         new STFReader.TokenProcessor("fadeout", () => { FadeOut = stf.ReadFloatBlock(STFReader.UNITS.None, null); }),
         new STFReader.TokenProcessor("states", () => {
             stf.MustMatch("(");
             var count = stf.ReadInt(null);
             stf.ParseBlock(new[] {
                 new STFReader.TokenProcessor("state", () => {
                     if (States.Count >= count)
                     {
                         STFException.TraceWarning(stf, "Skipped extra State");
                     }
                     else
                     {
                         States.Add(new LightState(stf));
                     }
                 }),
             });
             if (States.Count < count)
             {
                 STFException.TraceWarning(stf, (count - States.Count).ToString() + " missing State(s)");
             }
         }),
     });
 }
示例#6
0
        private static void ReadOrtsSignalFunctionTypes(STFReader stf)
        {
            stf.MustMatchBlockStart();
            int count      = stf.ReadInt(null);
            int tokensRead = 0;

            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("ortssignalfunctiontype", () => {
                    stf.MustMatchBlockStart();
                    if (tokensRead >= count)
                    {
                        STFException.TraceWarning(stf, "Skipped extra ORTSFunctionType");
                    }
                    else
                    {
                        string functionType = stf.ReadString();
                        // check agains default types
                        if (EnumExtension.GetValue(functionType, out SignalFunction result))
                        {
                            STFException.TraceWarning(stf, "Invalid definition of ORTSFunctionType, type is equal to MSTS defined type : " + functionType);
                        }
                        else if (functionType.StartsWith("OR_", StringComparison.OrdinalIgnoreCase) || functionType.StartsWith("ORTS", StringComparison.OrdinalIgnoreCase))
                        {
                            STFException.TraceWarning(stf, "Invalid definition of ORTSFunctionType, using reserved type name : " + functionType);
                        }
                        else
                        {
                            if (OrSignalTypes.Instance.FunctionTypes.Contains(functionType, StringComparer.OrdinalIgnoreCase))
                            {
                                STFException.TraceWarning(stf, "Skipped duplicate ORTSSignalFunction definition : " + functionType);
                            }
                            else
                            {
                                OrSignalTypes.Instance.FunctionTypes.Add(functionType);
                                tokensRead++;
                            }
                        }
                    }
                    stf.SkipRestOfBlock();
                }),
            });
示例#7
0
        public LightCollection(STFReader stf)
        {
            stf.MustMatch("(");
            stf.ReadInt(null); // count; ignore this because its not always correct
            stf.ParseBlock(new[] {
                new STFReader.TokenProcessor("light", () => { Lights.Add(new Light(Lights.Count, stf)); }),
            });
            if (Lights.Count == 0)
            {
                throw new InvalidDataException("lights with no lights");
            }

            // MSTSBin created reverse headlight cones automatically, so we shall do so too.
            foreach (var light in Lights.ToArray())
            {
                if (light.Type == LightType.Cone)
                {
                    Lights.Add(new Light(light, true));
                }
            }
        }
示例#8
0
        public TurntableFile(string filePath, string shapePath, List <MovingTable> movingTables, Simulator simulator)
        {
            if (!File.Exists(filePath))
            {
                return;
            }

            Trace.Write(" TURNTBL");

            using (STFReader stf = new STFReader(filePath, false))
            {
                var count = stf.ReadInt(null);
                stf.ParseBlock(new STFReader.TokenProcessor[] {
                    new STFReader.TokenProcessor("turntable", () => {
                        if (--count < 0)
                        {
                            STFException.TraceWarning(stf, "Skipped extra Turntable");
                        }
                        else
                        {
                            movingTables.Add(new Turntable(stf, simulator));
                        }
                    }),
                    new STFReader.TokenProcessor("transfertable", () => {
                        if (--count < 0)
                        {
                            STFException.TraceWarning(stf, "Skipped extra Transfertable");
                        }
                        else
                        {
                            movingTables.Add(new Transfertable(stf, simulator));
                        }
                    }),
                });
                if (count > 0)
                {
                    STFException.TraceWarning(stf, count + " missing Turntable(s)");
                }
            }
        }
        public SMSStreams(STFReader stf)
        {
            stf.MustMatch("(");
            var count = stf.ReadInt(null);

            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("stream", () => {
                    if (--count < 0)
                    {
                        STFException.TraceWarning(stf, "Skipped extra Stream");
                    }
                    else
                    {
                        Add(new SMSStream(stf));
                    }
                }),
            });
            if (count > 0)
            {
                STFException.TraceWarning(stf, count + " missing Stream(s)");
            }
        }
示例#10
0
        private void TryModify(int category, STFReader stf)
        {
            ActivityEvent origEvent;
            bool          wrongEventID = false;
            int           modifiedID   = -1;

            try
            {
                stf.MustMatchBlockStart();
                stf.MustMatch("id");
                stf.MustMatchBlockStart();
                modifiedID = stf.ReadInt(null);
                stf.MustMatchBlockEnd();
                origEvent = Find(x => x.ID == modifiedID);
                if (origEvent == null)
                {
                    wrongEventID = true;
                    Trace.TraceWarning("Skipped event {0} not present in base activity file", modifiedID);
                    stf.SkipRestOfBlock();
                }
                else
                {
                    wrongEventID = !TestMatch(category, origEvent);
                    if (!wrongEventID)
                    {
                        origEvent.Update(stf);
                    }
                    else
                    {
                        Trace.TraceWarning("Skipped event {0} of event category not matching with base activity file", modifiedID);
                        stf.SkipRestOfBlock();
                    }
                }
            }
            catch (Exception error)
            {
                Trace.WriteLine(new FileLoadException("Error in additional activity file", error));
            }
        }
示例#11
0
 public TurntableFile(string filePath, string shapePath, List <Turntable> turntables, Simulator simulator)
 {
     using (STFReader stf = new STFReader(filePath, false))
     {
         var count = stf.ReadInt(null);
         stf.ParseBlock(new STFReader.TokenProcessor[] {
             new STFReader.TokenProcessor("turntable", () => {
                 if (--count < 0)
                 {
                     STFException.TraceWarning(stf, "Skipped extra Turntable");
                 }
                 else
                 {
                     turntables.Add(new Turntable(stf, simulator));
                 }
             }),
         });
         if (count > 0)
         {
             STFException.TraceWarning(stf, count + " missing Turntable(s)");
         }
     }
 }
示例#12
0
 public TrackTypesFile(string fileName)
 {
     using (STFReader stf = new STFReader(fileName, false))
     {
         var count = stf.ReadInt(null);
         stf.ParseBlock(new STFReader.TokenProcessor[] {
             new STFReader.TokenProcessor("tracktype", () => {
                 if (--count < 0)
                 {
                     STFException.TraceWarning(stf, "Skipped extra TrackType");
                 }
                 else
                 {
                     Add(new TrackType(stf));
                 }
             }),
         });
         if (count > 0)
         {
             STFException.TraceWarning(stf, count + " missing TrackType(s)");
         }
     }
 }
示例#13
0
        public CarSpawnerBlock(STFReader stf, string shapePath, List <CarSpawnerList> carSpawnerLists, string listName)
        {
            var spawnerDataItems = new List <CarSpawnerItemData>();
            {
                var count = stf.ReadInt(null);
                stf.ParseBlock(new STFReader.TokenProcessor[] {
                    new STFReader.TokenProcessor("ignorexrotation", () => { IgnoreXRotation = stf.ReadBoolBlock(true); }),
                    new STFReader.TokenProcessor("carspawneritem", () => {
                        if (--count < 0)
                        {
                            STFException.TraceWarning(stf, "Skipped extra CarSpawnerItem");
                        }
                        else
                        {
                            var dataItem = new CarSpawnerItemData(stf, shapePath);
                            if (File.Exists(dataItem.name))
                            {
                                spawnerDataItems.Add(dataItem);
                            }
                            else
                            {
                                STFException.TraceWarning(stf, String.Format("Non-existent shape file {0} referenced", dataItem.name));
                            }
                        }
                    }),
                });
                if (count > 0)
                {
                    STFException.TraceWarning(stf, count + " missing CarSpawnerItem(s)");
                }
            }

            CarSpawnerList carSpawnerList = new CarSpawnerList(spawnerDataItems, listName, IgnoreXRotation);

            carSpawnerLists.Add(carSpawnerList);
        }
示例#14
0
        public CabViewControls(STFReader stf, string basepath)
        {
            stf.MustMatch("(");
            int count = stf.ReadInt(null);

            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("dial", () => { Add(new CVCDial(stf, basepath)); }),
                new STFReader.TokenProcessor("gauge", () => { Add(new CVCGauge(stf, basepath)); }),
                new STFReader.TokenProcessor("lever", () => { Add(new CVCDiscrete(stf, basepath)); }),
                new STFReader.TokenProcessor("twostate", () => { Add(new CVCDiscrete(stf, basepath)); }),
                new STFReader.TokenProcessor("tristate", () => { Add(new CVCDiscrete(stf, basepath)); }),
                new STFReader.TokenProcessor("multistatedisplay", () => { Add(new CVCMultiStateDisplay(stf, basepath)); }),
                new STFReader.TokenProcessor("cabsignaldisplay", () => { Add(new CVCSignal(stf, basepath)); }),
                new STFReader.TokenProcessor("digital", () => { Add(new CVCDigital(stf, basepath)); }),
                new STFReader.TokenProcessor("combinedcontrol", () => { Add(new CVCDiscrete(stf, basepath)); }),
                new STFReader.TokenProcessor("firebox", () => { Add(new CVCFirebox(stf, basepath)); }),
                new STFReader.TokenProcessor("digitalclock", () => { Add(new CVCDigitalClock(stf, basepath)); })
            });
            //TODO Uncomment when parsed all type

            /*
             * if (count != this.Count) STFException.ReportWarning(inf, "CabViewControl count mismatch");
             */
        }
示例#15
0
        /// <summary>
        /// Default constructor used during file parsing.
        /// </summary>
        /// <param name="stf">The STFreader containing the file stream</param>
        public SignalDrawLight(STFReader stf)
        {
            stf.MustMatchBlockStart();
            Index = stf.ReadInt(null);
            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("signalflags", () => {
                    stf.MustMatchBlockStart();
                    while (!stf.EndOfBlock())
                    {
                        switch (stf.ReadString().ToLower())
                        {
                        case "flashing":
                            Flashing = true;
                            break;

                        default:
                            stf.StepBackOneItem();
                            STFException.TraceInformation(stf, "Skipped unknown DrawLight flag " + stf.ReadString());
                            break;
                        }
                    }
                }),
            });
        }
示例#16
0
        public Lights(STFReader stf)
        {
            stf.MustMatchBlockStart();
            stf.ReadInt(null); // count; ignore this because its not always correct
            stf.ParseBlock(new[] {
                new STFReader.TokenProcessor("light", () => { Add(new Light(Count, stf)); }),
            });
            if (Count == 0)
            {
                throw new InvalidDataException("lights with no lights");
            }

            // MSTSBin created reverse headlight cones automatically, so we shall do so too.
            List <Light> reverseLights = new List <Light>();

            foreach (var light in this)
            {
                if (light.Type == LightType.Cone)
                {
                    reverseLights.Add(new Light(light, true));
                }
            }
            this.AddRange(reverseLights);
        }
示例#17
0
        }                                                // true for humans

        public CarSpawners(STFReader stf, string shapePath, string listName)
        {
            if (null == stf)
            {
                throw new ArgumentNullException(nameof(stf));
            }

            ListName = listName;
            int count = stf.ReadInt(null);

            stf.ParseBlock(new STFReader.TokenProcessor[] {
                new STFReader.TokenProcessor("ignorexrotation", () => { IgnoreXRotation = stf.ReadBoolBlock(true); }),
                new STFReader.TokenProcessor("carspawneritem", () => {
                    if (--count < 0)
                    {
                        STFException.TraceWarning(stf, "Skipped extra CarSpawnerItem");
                    }
                    else
                    {
                        CarSpawner dataItem = new CarSpawner(stf, shapePath);
                        if (File.Exists(dataItem.Name))
                        {
                            Add(dataItem);
                        }
                        else
                        {
                            STFException.TraceWarning(stf, $"Non-existent shape file {dataItem.Name} referenced");
                        }
                    }
                }),
            });
            if (count > 0)
            {
                STFException.TraceWarning(stf, count + " missing CarSpawnerItem(s)");
            }
        }
示例#18
0
        /// <summary>
        /// Parses all the parameters within the ENG file
        /// </summary>
        /// <param name="stf">eference to the ENG file reader</param>
        public void Parse(STFReader stf, MSTSDieselLocomotive loco)
        {
            stf.MustMatch("(");
            int count = stf.ReadInt(0);

            for (int i = 0; i < count; i++)
            {
                string setting = stf.ReadString().ToLower();
                if (setting == "diesel")
                {
                    DEList.Add(new DieselEngine());

                    DEList[i].Parse(stf, loco);
                    DEList[i].Initialize(true);
                }

                if ((!DEList[i].IsInitialized))
                {
                    STFException.TraceWarning(stf, "Diesel engine model has some errors - loading MSTS format");
                    DEList[i].InitFromMSTS((MSTSDieselLocomotive)Locomotive);
                    DEList[i].Initialize(true);
                }
            }
        }
示例#19
0
        public void Parse(string lowercasetoken, STFReader stf)
        {
            switch (lowercasetoken)
            {
            case "engine(trainbrakescontrollermaxsystempressure":
            case "engine(enginebrakescontrollermaxsystempressure":
                MaxPressurePSI = stf.ReadFloatBlock(STFReader.Units.PressureDefaultPSI, null);
                break;

            case "engine(trainbrakescontrollermaxreleaserate":
            case "engine(enginebrakescontrollermaxreleaserate":
                ReleaseRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null);
                break;

            case "engine(trainbrakescontrollermaxquickreleaserate":
            case "engine(enginebrakescontrollermaxquickreleaserate":
                QuickReleaseRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null);
                break;

            case "engine(trainbrakescontrollermaxapplicationrate":
            case "engine(enginebrakescontrollermaxapplicationrate":
                ApplyRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null);
                break;

            case "engine(trainbrakescontrolleremergencyapplicationrate":
            case "engine(enginebrakescontrolleremergencyapplicationrate":
                EmergencyRatePSIpS = stf.ReadFloatBlock(STFReader.Units.PressureRateDefaultPSIpS, null);
                break;

            case "engine(trainbrakescontrollerfullservicepressuredrop":
            case "engine(enginebrakescontrollerfullservicepressuredrop":
                FullServReductionPSI = stf.ReadFloatBlock(STFReader.Units.PressureDefaultPSI, null);
                break;

            case "engine(trainbrakescontrollerminpressurereduction":
            case "engine(enginebrakescontrollerminpressurereduction":
                MinReductionPSI = stf.ReadFloatBlock(STFReader.Units.PressureDefaultPSI, null);
                break;

            case "engine(enginecontrollers(brake_train":
            case "engine(enginecontrollers(brake_engine":
                stf.MustMatch("(");
                MinimumValue = stf.ReadFloat(STFReader.Units.None, null);
                MaximumValue = stf.ReadFloat(STFReader.Units.None, null);
                StepSize     = stf.ReadFloat(STFReader.Units.None, null);
                CurrentValue = stf.ReadFloat(STFReader.Units.None, null);
                string token = stf.ReadItem();                      // s/b numnotches
                if (string.Compare(token, "NumNotches", true) != 0) // handle error in gp38.eng where extra parameter provided before NumNotches statement
                {
                    stf.ReadItem();
                }
                stf.MustMatch("(");
                stf.ReadInt(null);
                stf.ParseBlock(new STFReader.TokenProcessor[] {
                    new STFReader.TokenProcessor("notch", () => {
                        stf.MustMatch("(");
                        float value = stf.ReadFloat(STFReader.Units.None, null);
                        int smooth  = stf.ReadInt(null);
                        string type = stf.ReadString();
                        Notches.Add(new MSTSNotch(value, smooth, type, stf));
                        if (type != ")")
                        {
                            stf.SkipRestOfBlock();
                        }
                    }),
                });
                break;

            case "engine(ortstrainbrakecontroller":
            case "engine(ortsenginebrakecontroller":
                if (Locomotive.Train as AITrain == null)
                {
                    ScriptName = stf.ReadStringBlock(null);
                }
                break;
            }
        }
示例#20
0
        /// <summary>
        /// Reads RailDriver calibration data from a ModernCalibration.rdm file
        /// This file is not in the usual STF format, but the STFReader can handle it okay.
        /// </summary>
        /// <param name="basePath"></param>
        void ReadCalibrationData(string basePath)
        {
            string file = basePath + "\\ModernCalibration.rdm";

            if (!File.Exists(file))
            {
                RegistryKey RK = Registry.LocalMachine.OpenSubKey("SOFTWARE\\PI Engineering\\PIBUS");
                if (RK != null)
                {
                    string dir = (string)RK.GetValue("RailDriver", null, RegistryValueOptions.None);
                    if (dir != null)
                    {
                        file = dir + "\\..\\controller\\ModernCalibration.rdm";
                    }
                }

                if (!File.Exists(file))
                {
                    SetLEDs(0, 0, 0);
                    Trace.TraceWarning("Cannot find RailDriver calibration file {0}", file);
                    return;
                }
            }
            // TODO: This is... kinda weird and cool at the same time. STF parsing being used on RailDriver's calebration file. Probably should be a dedicated parser, though.
            STFReader reader = new STFReader(file, false);

            while (!reader.Eof)
            {
                string token = reader.ReadItem();
                if (token == "Position")
                {
                    string name = reader.ReadItem();
                    int    min  = -1;
                    int    max  = -1;
                    while (token != "}")
                    {
                        token = reader.ReadItem();
                        if (token == "Min")
                        {
                            min = reader.ReadInt(-1);
                        }
                        else if (token == "Max")
                        {
                            max = reader.ReadInt(-1);
                        }
                    }
                    if (min >= 0 && max >= 0)
                    {
                        float v = .5f * (min + max);
                        switch (name)
                        {
                        case "Full Reversed": FullReversed = v; break;

                        case "Neutral": Neutral = v; break;

                        case "Full Forward": FullForward = v; break;

                        case "Full Throttle": FullThrottle = v; break;

                        case "Throttle Idle": ThrottleIdle = v; break;

                        case "Dynamic Brake": DynamicBrake = v; break;

                        case "Dynamic Brake Setup": DynamicBrakeSetup = v; break;

                        case "Auto Brake Released": AutoBrakeRelease = v; break;

                        case "Full Auto Brake (CS)": FullAutoBrake = v; break;

                        case "Emergency Brake (EMG)": EmergencyBrake = v; break;

                        case "Independent Brake Released": IndependentBrakeRelease = v; break;

                        case "Bail Off Engaged (in Released position)": BailOffEngagedRelease = v; break;

                        case "Independent Brake Full": IndependentBrakeFull = v; break;

                        case "Bail Off Engaged (in Full position)": BailOffEngagedFull = v; break;

                        case "Bail Off Disengaged (in Released position)": BailOffDisengagedRelease = v; break;

                        case "Bail Off Disengaged (in Full position)": BailOffDisengagedFull = v; break;

                        case "Rotary Switch 1-Position 1(OFF)": Rotary1Position1 = v; break;

                        case "Rotary Switch 1-Position 2(SLOW)": Rotary1Position2 = v; break;

                        case "Rotary Switch 1-Position 3(FULL)": Rotary1Position3 = v; break;

                        case "Rotary Switch 2-Position 1(OFF)": Rotary2Position1 = v; break;

                        case "Rotary Switch 2-Position 2(DIM)": Rotary2Position2 = v; break;

                        case "Rotary Switch 2-Position 3(FULL)": Rotary2Position3 = v; break;

                        default: STFException.TraceInformation(reader, "Skipped unknown calibration value " + name); break;
                        }
                    }
                }
            }
        }
示例#21
0
        /// <summary>
        /// Parse the wag file parameters required for the simulator and viewer classes
        /// </summary>
        public override void Parse(string lowercasetoken, STFReader stf)
        {
            switch (lowercasetoken)
            {
            case "engine(dieselengineidlerpm": IdleRPM = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;

            case "engine(dieselenginemaxrpm": MaxRPM = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;

            case "engine(dieselenginemaxrpmchangerate": MaxRPMChangeRate = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;

            case "engine(ortsdieselenginemaxpower": MaximumDieselEnginePowerW = stf.ReadFloatBlock(STFReader.UNITS.Power, null); break;

            case "engine(effects(dieselspecialeffects": ParseEffects(lowercasetoken, stf); break;

            case "engine(dieselsmokeeffectinitialsmokerate": InitialExhaust = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;

            case "engine(dieselsmokeeffectinitialmagnitude": InitialMagnitude = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;

            case "engine(dieselsmokeeffectmaxsmokerate": MaxExhaust = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;

            case "engine(dieselsmokeeffectmaxmagnitude": MaxMagnitude = stf.ReadFloatBlock(STFReader.UNITS.None, null); break;

            case "engine(ortsdieselengines": DieselEngines = new DieselEngines(this, stf); break;

            case "engine(maxdiesellevel": MaxDieselLevelL = stf.ReadFloatBlock(STFReader.UNITS.Volume, null); break;

            case "engine(dieselusedperhouratmaxpower": DieselUsedPerHourAtMaxPowerL = stf.ReadFloatBlock(STFReader.UNITS.Volume, null); break;

            case "engine(dieselusedperhouratidle": DieselUsedPerHourAtIdleL = stf.ReadFloatBlock(STFReader.UNITS.Volume, null); break;

            case "engine(maxoilpressure": DieselMaxOilPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, 120f); break;

            case "engine(ortsminoilpressure": DieselMinOilPressurePSI = stf.ReadFloatBlock(STFReader.UNITS.PressureDefaultPSI, 40f); break;

            case "engine(maxtemperature": DieselMaxTemperatureDeg = stf.ReadFloatBlock(STFReader.UNITS.TemperatureDifference, 100f); break;

            case "engine(ortsdieselcooling": DieselEngineCooling = (DieselEngine.Cooling)stf.ReadInt((int)DieselEngine.Cooling.Proportional); break;

            default:
                GearBox.Parse(lowercasetoken, stf);
                base.Parse(lowercasetoken, stf); break;
            }

            if (IdleRPM != 0 && MaxRPM != 0 && MaxRPMChangeRate != 0)
            {
                PercentChangePerSec = MaxRPMChangeRate / (MaxRPM - IdleRPM);
                EngineRPM           = IdleRPM;
            }
        }
示例#22
0
 internal RouteStart(STFReader stf)
 {
     stf.MustMatchBlockStart();
     location = new WorldLocation(stf.ReadInt(null), stf.ReadInt(null), stf.ReadFloat(null), 0f, stf.ReadFloat(null));
     stf.SkipRestOfBlock();
 }
示例#23
0
 protected virtual void ParseJustification(STFReader stf)
 {
     stf.MustMatch("(");
     Justification = stf.ReadInt(3);
     stf.SkipRestOfBlock();
 }
示例#24
0
 public ENVFileSkyLayer(STFReader stf)
 {
     stf.MustMatch("(");
     stf.ParseBlock(new STFReader.TokenProcessor[] {
         new STFReader.TokenProcessor("world_sky_layer_fadein", () => { stf.MustMatch("("); Fadein_Begin_Time = stf.ReadString(); Fadein_End_Time = stf.ReadString(); stf.SkipRestOfBlock(); }),
         new STFReader.TokenProcessor("world_anim_shader", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
                 new STFReader.TokenProcessor("world_anim_shader_frames", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
                         new STFReader.TokenProcessor("world_anim_shader_frame", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
                                 new STFReader.TokenProcessor("world_anim_shader_frame_uvtiles", () => { stf.MustMatch("("); TileX = stf.ReadFloat(STFReader.UNITS.Any, 1.0f); TileY = stf.ReadFloat(STFReader.UNITS.Any, 1.0f); stf.ParseBlock(new STFReader.TokenProcessor[] {
                                     }); }),
                             }); }),
                     }); }),
                 new STFReader.TokenProcessor("world_shader", () => { stf.MustMatch("("); TextureMode = stf.ReadString(); stf.ParseBlock(new STFReader.TokenProcessor[] {
                         new STFReader.TokenProcessor("terrain_texslots", () => { stf.MustMatch("("); stf.ReadInt(null) /*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
                                 new STFReader.TokenProcessor("terrain_texslot", () => { stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }),
                             }); }),
                     }); }),
             }); }),
     });
 }
示例#25
0
 public ENVFileWaterLayer(STFReader stf)
 {
     stf.MustMatch("(");
     stf.ParseBlock(new STFReader.TokenProcessor[] {
         new STFReader.TokenProcessor("world_water_layer_height", () => { Height = stf.ReadFloatBlock(STFReader.UNITS.Distance, null); }),
         new STFReader.TokenProcessor("world_anim_shader", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
                 new STFReader.TokenProcessor("world_shader", () => { stf.MustMatch("("); stf.ReadString() /*TextureMode*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
                         new STFReader.TokenProcessor("terrain_texslots", () => { stf.MustMatch("("); stf.ReadInt(null) /*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
                                 new STFReader.TokenProcessor("terrain_texslot", () => { stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }),
                             }); }),
                     }); }),
             }); }),
     });
 }
示例#26
0
        public static Interpolator2D CreateInterpolator2D(this STFReader stf, bool tab)
        {
            List <double>       xlist = new List <double>();
            List <Interpolator> ilist = new List <Interpolator>();

            bool errorFound = false;

            if (tab)
            {
                stf.MustMatchBlockStart();
                int numOfRows = stf.ReadInt(0);
                if (numOfRows < 2)
                {
                    STFException.TraceWarning(stf, "Interpolator must have at least two rows.");
                    errorFound = true;
                }
                int    numOfColumns = stf.ReadInt(0);
                string header       = stf.ReadString().ToLower();
                if (header == "throttle")
                {
                    stf.MustMatchBlockStart();
                    int numOfThrottleValues = 0;
                    while (!stf.EndOfBlock())
                    {
                        xlist.Add(stf.ReadFloat(STFReader.Units.None, 0f));
                        ilist.Add(new Interpolator(numOfRows));
                        numOfThrottleValues++;
                    }
                    if (numOfThrottleValues != (numOfColumns - 1))
                    {
                        STFException.TraceWarning(stf, "Interpolator throttle vs. num of columns mismatch.");
                        errorFound = true;
                    }

                    if (numOfColumns < 3)
                    {
                        STFException.TraceWarning(stf, "Interpolator must have at least three columns.");
                        errorFound = true;
                    }

                    int    numofData  = 0;
                    string tableLabel = stf.ReadString().ToLower();
                    if (tableLabel == "table")
                    {
                        stf.MustMatchBlockStart();
                        for (int i = 0; i < numOfRows; i++)
                        {
                            float x = stf.ReadFloat(STFReader.Units.SpeedDefaultMPH, 0);
                            numofData++;
                            for (int j = 0; j < numOfColumns - 1; j++)
                            {
                                if (j >= ilist.Count)
                                {
                                    STFException.TraceWarning(stf, "Interpolator throttle vs. num of columns mismatch. (missing some throttle values)");
                                    errorFound = true;
                                }
                                ilist[j][x] = stf.ReadFloat(STFReader.Units.Force, 0);
                                numofData++;
                            }
                        }
                        stf.SkipRestOfBlock();
                    }
                    else
                    {
                        STFException.TraceWarning(stf, "Interpolator didn't find a table to load.");
                        errorFound = true;
                    }
                    //check the table for inconsistencies

                    foreach (Interpolator checkMe in ilist)
                    {
                        if (checkMe.Size != numOfRows)
                        {
                            STFException.TraceWarning(stf, "Interpolator has found a mismatch between num of rows declared and num of rows given.");
                            errorFound = true;
                        }
                        double dx = (checkMe.MaxX() - checkMe.MinX()) * 0.1f;
                        if (dx <= 0f)
                        {
                            STFException.TraceWarning(stf, "Interpolator has found X data error - x values must be increasing. (Possible row number mismatch)");
                            errorFound = true;
                        }
                        else
                        {
                            for (double x = checkMe.MinX(); x <= checkMe.MaxX(); x += dx)
                            {
                                if (double.IsNaN(checkMe[x]))
                                {
                                    STFException.TraceWarning(stf, "Interpolator has found X data error - x values must be increasing. (Possible row number mismatch)");
                                    errorFound = true;
                                    break;
                                }
                            }
                        }
                    }

                    if (numofData != (numOfRows * numOfColumns))
                    {
                        STFException.TraceWarning(stf, "Interpolator has found a mismatch: num of data doesn't fit the header information.");
                        errorFound = true;
                    }
                }
                else
                {
                    STFException.TraceWarning(stf, "Interpolator must have a 'throttle' header row.");
                    errorFound = true;
                }
                stf.SkipRestOfBlock();
            }
            else
            {
                stf.MustMatchBlockStart();
                while (!stf.EndOfBlock())
                {
                    xlist.Add(stf.ReadFloat(STFReader.Units.Any, null));
                    ilist.Add(stf.CreateInterpolator());
                }
            }


            int n = xlist.Count;

            if (n < 2)
            {
                STFException.TraceWarning(stf, "Interpolator must have at least two x values.");
                errorFound = true;
            }
            double[]       xArray = new double[n];
            Interpolator[] yArray = new Interpolator[n];
            for (int i = 0; i < n; i++)
            {
                xArray[i] = xlist[i];
                yArray[i] = ilist[i];
                if (i > 0 && xArray[i - 1] >= xArray[i])
                {
                    STFException.TraceWarning(stf, "Interpolator x values must be increasing.");
                }
            }
            if (errorFound)
            {
                STFException.TraceWarning(stf, "Errors found in the Interpolator definition!!! The Interpolator will not work correctly!");
            }

            Interpolator2D result = new Interpolator2D(xArray, yArray);

            return(result);
        }
示例#27
0
 public DisableTrigger(STFReader f)
 {
     f.MustMatch("(");
     TriggerID = f.ReadInt(null);
     f.SkipRestOfBlock();
 }
示例#28
0
 public override int ReadInt()
 {
     return(stf.ReadInt(null));
 }
示例#29
0
 public ENVFileSkySatellite(STFReader stf)
 {
     stf.MustMatch("(");
     stf.ParseBlock(new STFReader.TokenProcessor[] {
         new STFReader.TokenProcessor("world_anim_shader", () => { stf.MustMatch("("); stf.ParseBlock(new STFReader.TokenProcessor[] {
                 new STFReader.TokenProcessor("world_shader", () => { stf.MustMatch("("); TextureMode = stf.ReadString(); stf.ParseBlock(new STFReader.TokenProcessor[] {
                         new STFReader.TokenProcessor("terrain_texslots", () => { stf.MustMatch("("); stf.ReadInt(null) /*Count*/; stf.ParseBlock(new STFReader.TokenProcessor[] {
                                 new STFReader.TokenProcessor("terrain_texslot", () => { stf.MustMatch("("); TextureName = stf.ReadString(); stf.SkipRestOfBlock(); }),
                             }); }),
                     }); }),
             }); }),
     });
 }
示例#30
0
        public CVCDiscrete(STFReader stf, string basepath)
        {
//            try
            {
                stf.MustMatch("(");
                stf.ParseBlock(new STFReader.TokenProcessor[] {
                    new STFReader.TokenProcessor("type", () => { ParseType(stf); }),
                    new STFReader.TokenProcessor("position", () => { ParsePosition(stf); }),
                    new STFReader.TokenProcessor("scalerange", () => { ParseScaleRange(stf); }),
                    new STFReader.TokenProcessor("graphic", () => { ParseGraphic(stf, basepath); }),
                    new STFReader.TokenProcessor("style", () => { ParseStyle(stf); }),
                    new STFReader.TokenProcessor("units", () => { ParseUnits(stf); }),
                    new STFReader.TokenProcessor("mousecontrol", () => { MouseControl = stf.ReadBoolBlock(false); }),
                    new STFReader.TokenProcessor("orientation", () => { Orientation = stf.ReadIntBlock(null); }),
                    new STFReader.TokenProcessor("dirincrease", () => { Direction = stf.ReadIntBlock(null); }),

                    new STFReader.TokenProcessor("numframes", () => {
                        stf.MustMatch("(");
                        FramesCount = stf.ReadInt(null);
                        FramesX     = stf.ReadInt(null);
                        FramesY     = stf.ReadInt(null);
                        stf.SkipRestOfBlock();
                    }),
                    // <CJComment> Would like to revise this, as it is difficult to follow and debug.
                    // Can't do that until interaction of ScaleRange, NumFrames, NumPositions and NumValues is more fully specified.
                    // What is needed is samples of data that must be accommodated.
                    // Some decisions appear unwise but they might be a pragmatic solution to a real problem. </CJComment>
                    //
                    // Code accommodates:
                    // - NumValues before NumPositions or the other way round.
                    // - More NumValues than NumPositions and the other way round - perhaps unwise.
                    // - The count of NumFrames, NumValues and NumPositions is ignored - perhaps unwise.
                    // - Abbreviated definitions so that values at intermediate unspecified positions can be omitted.
                    //   Strangely, these values are set to 0 and worked out later when drawing.
                    // Max and min NumValues which don't match the ScaleRange are ignored - perhaps unwise.
                    new STFReader.TokenProcessor("numpositions", () => {
                        stf.MustMatch("(");
                        // If Positions are not filled before by Values
                        bool shouldFill = (Positions.Count == 0);
                        numPositions    = stf.ReadInt(null); // Number of Positions

                        var minPosition   = 0;
                        var positionsRead = 0;
                        while (!stf.EndOfBlock())
                        {
                            int p = stf.ReadInt(null);

                            minPosition = positionsRead == 0 ? p : Math.Min(minPosition, p);  // used to get correct offset
                            positionsRead++;

                            // If Positions are not filled before by Values
                            if (shouldFill)
                            {
                                Positions.Add(p);
                            }
                        }

                        // If positions do not start at 0, add offset to shift them all so they do.
                        // An example of this is RENFE 400 (from http://www.trensim.com/lib/msts/index.php?act=view&id=186)
                        // which has a COMBINED_CONTROL with:
                        //   NumPositions ( 21 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 )
                        // Also handles definitions with position in reverse order, e.g.
                        //   NumPositions ( 5 8 7 2 1 0 )
                        positionsRead++;

                        if (minPosition < 0)
                        {
                            for (int iPos = 0; iPos <= Positions.Count - 1; iPos++)
                            {
                                Positions[iPos] -= minPosition;
                            }
                        }

                        // This is a hack for SLI locomotives which have the positions listed as "1056964608 0 0 0 ...".
                        if (Positions.Any(p => p > 0xFFFF))
                        {
                            STFException.TraceInformation(stf, "Renumbering cab control positions from zero due to value > 0xFFFF");
                            for (var i = 0; i < Positions.Count; i++)
                            {
                                Positions[i] = i;
                            }
                        }

                        // Check if eligible for filling

                        if (Positions.Count > 1 && Positions[0] != 0)
                        {
                            canFill = false;
                        }
                        else
                        {
                            for (var iPos = 1; iPos <= Positions.Count - 1; iPos++)
                            {
                                if (Positions[iPos] > Positions[iPos - 1])
                                {
                                    continue;
                                }
                                canFill = false;
                                break;
                            }
                        }

                        // This is a protection against GP40 locomotives that erroneously have positions pointing beyond frame count limit.

                        if (Positions.Count > 1 && canFill && Positions.Count < FramesCount && Positions[Positions.Count - 1] >= FramesCount && Positions[0] == 0)
                        {
                            STFException.TraceInformation(stf, "Some NumPositions entries refer to non-exisiting frames, trying to renumber");
                            Positions[Positions.Count - 1] = FramesCount - 1;
                            for (var iPos = Positions.Count - 2; iPos >= 1; iPos--)
                            {
                                if ((Positions[iPos] >= FramesCount || Positions[iPos] >= Positions[iPos + 1]))
                                {
                                    Positions[iPos] = Positions[iPos + 1] - 1;
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                    }),
                    new STFReader.TokenProcessor("numvalues", () => {
                        stf.MustMatch("(");
                        var numValues = stf.ReadDouble(null); // Number of Values
                        while (!stf.EndOfBlock())
                        {
                            double v = stf.ReadDouble(null);
                            // If the Positions are less than expected add new Position(s)
                            while (Positions.Count <= _ValuesRead)
                            {
                                Positions.Add(_ValuesRead);
                            }
                            // Avoid later repositioning, put every value to its Position
                            // But before resize Values if needed
                            if (numValues != numPositions)
                            {
                                while (Values.Count <= Positions[_ValuesRead])
                                {
                                    Values.Add(0);
                                }
                                // Avoid later repositioning, put every value to its Position
                                Values[Positions[_ValuesRead]] = v;
                            }
                            Values.Add(v);
                            _ValuesRead++;
                        }
                    }),
                });

                // If no ACE, just don't need any fixup
                // Because Values are tied to the image Frame to be shown
                if (string.IsNullOrEmpty(ACEFile))
                {
                    return;
                }

                // Now, we have an ACE.

                // If read any Values, or the control requires Values to control
                //     The twostate, tristate, signal displays are not in these
                // Need check the Values collection for validity
                if (_ValuesRead > 0 || ControlStyle == CABViewControlStyles.SPRUNG || ControlStyle == CABViewControlStyles.NOT_SPRUNG ||
                    FramesCount > 0 || (FramesX > 0 && FramesY > 0))
                {
                    // Check max number of Frames
                    if (FramesCount == 0)
                    {
                        // Check valid Frame information
                        if (FramesX == 0 || FramesY == 0)
                        {
                            // Give up, it won't work
                            // Because later we won't know how to display frames from that
                            Trace.TraceWarning("Invalid Frames information given for ACE {0} in {1}", ACEFile, stf.FileName);
                            ACEFile = "";
                            return;
                        }

                        // Valid frames info, set FramesCount
                        FramesCount = FramesX * FramesY;
                    }

                    // Now we have an ACE and Frames for it.

                    // Only shuffle data in following cases

                    if (Values.Count != Positions.Count || (Values.Count < FramesCount & canFill) || (Values.Count > 0 && Values[0] == Values[Values.Count - 1] && Values[0] == 0))
                    {
                        // Fixup Positions and Values collections first

                        // If the read Positions and Values are not match
                        // Or we didn't read Values but have Frames to draw
                        // Do not test if FramesCount equals Values count, we trust in the creator -
                        //     maybe did not want to display all Frames
                        // (If there are more Values than Frames it will checked at draw time)
                        // Need to fix the whole Values
                        if (Positions.Count != _ValuesRead || (FramesCount > 0 && (Values.Count == 0 || Values.Count == 1)))
                        {
                            //This if clause covers among others following cases:
                            // Case 1 (e.g. engine brake lever of Dash 9):
                            //NumFrames ( 22 11 2 )
                            //NumPositions ( 1 0 )
                            //NumValues ( 1 0 )
                            //Orientation ( 1 )
                            //DirIncrease ( 1 )
                            //ScaleRange ( 0 1 )
                            //
                            // Case 2 (e.g. throttle lever of Acela):
                            //NumFrames ( 25 5 5 )
                            //NumPositions ( 0 )
                            //NumValues ( 0 )
                            //Orientation ( 1 )
                            //DirIncrease ( 1 )
                            //ScaleRange ( 0 1 )
                            //
                            // Clear existing
                            Positions.Clear();
                            Values.Clear();

                            // Add the two sure positions, the two ends
                            Positions.Add(0);
                            // We will need the FramesCount later!
                            // We use Positions only here
                            Positions.Add(FramesCount);

                            // Fill empty Values
                            for (int i = 0; i < FramesCount; i++)
                            {
                                Values.Add(0);
                            }
                            Values[0] = MinValue;

                            Values.Add(MaxValue);
                        }
                        else if (Values.Count == 2 && Values[0] == 0 && Values[1] < MaxValue && Positions[0] == 0 && Positions[1] == 1 && Values.Count < FramesCount)
                        {
                            //This if clause covers among others following cases:
                            // Case 1 (e.g. engine brake lever of gp38):
                            //NumFrames ( 18 2 9 )
                            //NumPositions ( 2 0 1 )
                            //NumValues ( 2 0 0.3 )
                            //Orientation ( 0 )
                            //DirIncrease ( 0 )
                            //ScaleRange ( 0 1 )
                            Positions.Add(FramesCount);
                            // Fill empty Values
                            for (int i = Values.Count; i < FramesCount; i++)
                            {
                                Values.Add(Values[1]);
                            }
                            Values.Add(MaxValue);
                        }

                        else
                        {
                            //This if clause covers among others following cases:
                            // Case 1 (e.g. train brake lever of Acela):
                            //NumFrames ( 12 4 3 )
                            //NumPositions ( 5 0 1 9 10 11 )
                            //NumValues ( 5 0 0.2 0.85 0.9 0.95 )
                            //Orientation ( 1 )
                            //DirIncrease ( 1 )
                            //ScaleRange ( 0 1 )
                            //
                            // Fill empty Values
                            int iValues = 1;
                            for (int i = 1; i < FramesCount && i <= Positions.Count - 1 && Values.Count < FramesCount; i++)
                            {
                                var deltaPos = Positions[i] - Positions[i - 1];
                                while (deltaPos > 1 && Values.Count < FramesCount)
                                {
                                    Values.Insert(iValues, 0);
                                    iValues++;
                                    deltaPos--;
                                }
                                iValues++;
                            }

                            // Add the maximums to the end, the Value will be removed
                            // We use Positions only here
                            if (Values.Count > 0 && Values[0] <= Values[Values.Count - 1])
                            {
                                Values.Add(MaxValue);
                            }
                            else if (Values.Count > 0 && Values[0] > Values[Values.Count - 1])
                            {
                                Values.Add(MinValue);
                            }
                        }

                        // OK, we have a valid size of Positions and Values

                        // Now it is the time for checking holes in the given data
                        if ((Positions.Count < FramesCount - 1 && Values[0] <= Values[Values.Count - 1]) || (Values.Count > 1 && Values[0] == Values[Values.Count - 2] && Values[0] == 0))
                        {
                            int j = 1;
                            int p = 0;
                            // Skip the 0 element, that is the default MinValue
                            for (int i = 1; i < Positions.Count; i++)
                            {
                                // Found a hole
                                if (Positions[i] != p + 1)
                                {
                                    // Iterate to the next valid data and fill the hole
                                    for (j = p + 1; j < Positions[i]; j++)
                                    {
                                        // Extrapolate into the hole
                                        Values[j] = MathHelper.Lerp((float)Values[p], (float)Values[Positions[i]], (float)j / (float)Positions[i]);
                                    }
                                }
                                p = Positions[i];
                            }
                        }

                        // Don't need the MaxValue added before, remove it
                        Values.RemoveAt(Values.Count - 1);
                    }
                }

                // MSTS ignores/overrides various settings by the following exceptional cases:
                if (ControlType == CABViewControlTypes.CP_HANDLE)
                {
                    ControlStyle = CABViewControlStyles.NOT_SPRUNG;
                }
                if (ControlType == CABViewControlTypes.PANTOGRAPH || ControlType == CABViewControlTypes.PANTOGRAPH2)
                {
                    ControlStyle = CABViewControlStyles.ONOFF;
                }
                if (ControlType == CABViewControlTypes.HORN || ControlType == CABViewControlTypes.SANDERS || ControlType == CABViewControlTypes.BELL ||
                    ControlType == CABViewControlTypes.RESET)
                {
                    ControlStyle = CABViewControlStyles.WHILE_PRESSED;
                }
                if (ControlType == CABViewControlTypes.DIRECTION && Orientation == 0)
                {
                    Direction = 1 - Direction;
                }
            }
//            catch (Exception error)
//            {
//                if (error is STFException) // Parsing error, so pass it on
//                    throw;
//                else                       // Unexpected error, so provide a hint
//                    throw new STFException(stf, "Problem with NumPositions/NumValues/NumFrames/ScaleRange");
//            } // End of Need check the Values collection for validity
        } // End of Constructor