Пример #1
0
        /// <summary>Parses an XML motor table node</summary>
        /// <param name="node">The node</param>
        /// <param name="Tables">The motor sound tables to assign this node's contents to</param>
        /// <param name="Position">The default sound position</param>
        /// <param name="Radius">The default sound radius</param>
        private static void ParseMotorSoundTableNode(XmlNode node, ref TrainManager.MotorSoundTable[] Tables, Vector3 Position, double Radius)
        {
            foreach (XmlNode c in node.ChildNodes)
            {
                int idx;

                if (!NumberFormats.TryParseIntVb6(c.Name, out idx))
                {
                    continue;
                }

                for (int i = 0; i < Tables.Length; i++)
                {
                    Tables[i].Buffer = null;
                    Tables[i].Source = null;

                    for (int j = 0; j > Tables[i].Entries.Length; j++)
                    {
                        if (idx == Tables[i].Entries[j].SoundIndex)
                        {
                            ParseNode(c, out Tables[i].Entries[j].Buffer, ref Position, Radius);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Function to parse the contents of TravelData class
        /// </summary>
        /// <param name="FileName">The filename of the containing XML file</param>
        /// <param name="SectionElement">The XElement to parse</param>
        /// <param name="Data">Travel data to which the parse results apply</param>
        private static void ParseTravelDataNode(string FileName, XElement SectionElement, TravelData Data)
        {
            string Section = SectionElement.Name.LocalName;

            double Decelerate  = 0.0;
            double Accelerate  = 0.0;
            double TargetSpeed = 0.0;

            foreach (XElement KeyNode in SectionElement.Elements())
            {
                string Key        = KeyNode.Name.LocalName;
                string Value      = KeyNode.Value;
                int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                switch (Key.ToLowerInvariant())
                {
                case "decelerate":
                    if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out Decelerate) || Decelerate < 0.0)
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a non-negative floating-point number in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    }
                    break;

                case "position":
                case "stopposition":
                    if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out Data.Position))
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    }
                    break;

                case "accelerate":
                    if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out Accelerate) || Accelerate < 0.0)
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a non-negative floating-point number in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    }
                    break;

                case "targetspeed":
                    if (Value.Any() && !NumberFormats.TryParseDoubleVb6(Value, out TargetSpeed) || TargetSpeed < 0.0)
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a non-negative floating-point number in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    }
                    break;

                case "rail":
                    if (Value.Any() && !NumberFormats.TryParseIntVb6(Value, out Data.RailIndex) || Data.RailIndex < 0)
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a non-negative integer number in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                        Data.RailIndex = 0;
                    }
                    break;
                }
            }

            Data.Decelerate  = -Decelerate / 3.6;
            Data.Accelerate  = Accelerate / 3.6;
            Data.TargetSpeed = TargetSpeed / 3.6;
        }
Пример #3
0
        /// <summary>Parses any command-line arguments passed to the main program</summary>
        /// <param name="Arguments">A string array of arguments</param>
        /// <param name="Result">The main dialog result (Used to launch)</param>
        internal static void ParseArguments(string[] Arguments, ref formMain.MainDialogResult Result)
        {
            if (Arguments.Length == 0)
            {
                return;
            }
            for (int i = 0; i < Arguments.Length; i++)
            {
                int equals = Arguments[i].IndexOf('=');
                if (equals >= 0)
                {
                    string key   = Arguments[i].Substring(0, equals).Trim(new char[] { }).ToLowerInvariant();
                    string value = Arguments[i].Substring(equals + 1).Trim(new char[] { });
                    switch (key)
                    {
                    case "/route":
                        Result.RouteFile     = value;
                        Result.RouteEncoding = TextEncoding.GetSystemEncodingFromFile(Result.RouteFile);
                        break;

                    case "/train":
                        Result.TrainFolder   = value;
                        Result.TrainEncoding = TextEncoding.GetSystemEncodingFromFile(Result.TrainFolder, "train.txt");
                        break;

                    case "/station":
                        Result.InitialStation = value;
                        break;

                    case "/time":
                        Interface.TryParseTime(value, out Result.StartTime);
                        break;

                    case "/ai":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.AIDriver = true;
                        }
                        break;

                    case "/fullscreen":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.FullScreen = true;
                        }
                        break;

                    case "/width":
                        NumberFormats.TryParseIntVb6(value, out Result.Width);
                        break;

                    case "/height":
                        NumberFormats.TryParseIntVb6(value, out Result.Height);
                        break;
                    }
                }
            }
        }
Пример #4
0
        private int[] FindIndices(ref string Command, Expression Expression)
        {
            int[] commandIndices = { 0, 0 };
            if (Command != null && Command.EndsWith(")"))
            {
                for (int k = Command.Length - 2; k >= 0; k--)
                {
                    if (Command[k] == '(')
                    {
                        string Indices = Command.Substring(k + 1, Command.Length - k - 2).TrimStart();
                        Command = Command.Substring(0, k).TrimEnd();
                        int h = Indices.IndexOf(";", StringComparison.Ordinal);
                        if (h >= 0)
                        {
                            string a = Indices.Substring(0, h).TrimEnd();
                            string b = Indices.Substring(h + 1).TrimStart();
                            if (a.Length > 0 && !NumberFormats.TryParseIntVb6(a, out commandIndices[0]))
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid first index appeared at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File + ".");
                                Command = null;
                            }
                            if (b.Length > 0 && !NumberFormats.TryParseIntVb6(b, out commandIndices[1]))
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid second index appeared at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File + ".");
                                Command = null;
                            }
                        }
                        else
                        {
                            if (Indices.Length > 0 && !NumberFormats.TryParseIntVb6(Indices, out commandIndices[0]))
                            {
                                if (Indices.ToLowerInvariant() != "c" || Command.ToLowerInvariant() != "route.comment")
                                {
                                    // (C) used in route comment to represent copyright symbol, so not an error
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File + ".");
                                    Command = null;
                                }
                            }
                        }
                        break;
                    }
                }
            }

            return(commandIndices);
        }
Пример #5
0
 /// <summary>Parses an XML motor table node</summary>
 /// <param name="node">The node</param>
 /// <param name="Tables">The motor sound tables to assign this node's contents to</param>
 /// <param name="Position">The default sound position</param>
 /// <param name="Radius">The default sound radius</param>
 private void ParseMotorSoundTableNode(XmlNode node, ref BVEMotorSoundTable[] Tables, Vector3 Position, double Radius)
 {
     foreach (XmlNode c in node.ChildNodes)
     {
         int idx = -1;
         if (c.Name.ToLowerInvariant() != "sound")
         {
             Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid array node " + c.Name + " in XML node " + node.Name);
         }
         else
         {
             for (int i = 0; i < c.ChildNodes.Count; i++)
             {
                 if (c.ChildNodes[i].Name.ToLowerInvariant() == "index")
                 {
                     if (!NumberFormats.TryParseIntVb6(c.ChildNodes[i].InnerText.ToLowerInvariant(), out idx))
                     {
                         Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name);
                         return;
                     }
                     break;
                 }
             }
             if (idx >= 0)
             {
                 for (int i = 0; i < Tables.Length; i++)
                 {
                     Tables[i].Buffer = null;
                     Tables[i].Source = null;
                     for (int j = 0; j < Tables[i].Entries.Length; j++)
                     {
                         if (idx == Tables[i].Entries[j].SoundIndex)
                         {
                             ParseNode(c, out Tables[i].Entries[j].Buffer, ref Position, Radius);
                         }
                     }
                 }
             }
             else
             {
                 Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name);
             }
         }
     }
 }
Пример #6
0
 /// <summary>Parses an XML node containing a list of sounds into a car sound array</summary>
 /// <param name="node">The node to parse</param>
 /// <param name="Sounds">The car sound array</param>
 /// <param name="Position">The default position of the sound (May be overriden by any node)</param>
 /// <param name="Radius">The default radius of the sound (May be overriden by any node)</param>
 private void ParseDictionaryNode(XmlNode node, out Dictionary <int, CarSound> Sounds, Vector3 Position, double Radius)
 {
     Sounds = new Dictionary <int, CarSound>();
     foreach (XmlNode c in node.ChildNodes)
     {
         int idx = -1;
         if (c.Name.ToLowerInvariant() != "sound")
         {
             Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid array node " + c.Name + " in XML node " + node.Name);
         }
         else
         {
             for (int i = 0; i < c.ChildNodes.Count; i++)
             {
                 if (c.ChildNodes[i].Name.ToLowerInvariant() == "index")
                 {
                     if (!NumberFormats.TryParseIntVb6(c.ChildNodes[i].InnerText.ToLowerInvariant(), out idx))
                     {
                         Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name);
                         return;
                     }
                     break;
                 }
             }
             if (idx >= 0)
             {
                 CarSound sound;
                 ParseNode(c, out sound, Position, Radius);
                 if (Sounds.ContainsKey(idx))
                 {
                     Sounds[idx] = sound;
                 }
                 else
                 {
                     Sounds.Add(idx, sound);
                 }
             }
             else
             {
                 Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name);
             }
         }
     }
 }
Пример #7
0
        private static void ParseArrayNode <T>(string basePath, XElement parentNode, ICollection <SoundElement> elements) where T : SoundElement <int>, new()
        {
            foreach (XElement childNode in parentNode.Elements())
            {
                if (childNode.Name.LocalName.ToLowerInvariant() != "sound")
                {
                    Interface.AddMessage(MessageType.Error, false, $"Invalid array node {childNode.Name.LocalName} in XML node {parentNode.Name.LocalName} at line {((IXmlLineInfo)childNode).LineNumber}");
                }
                else
                {
                    int      idx;
                    XElement indexNode = childNode.Element("Index");

                    if (indexNode == null)
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Invalid array index {childNode.Name.LocalName} in XML node {parentNode.Name.LocalName} at line {((IXmlLineInfo)childNode).LineNumber}");
                        return;
                    }

                    if (!NumberFormats.TryParseIntVb6(indexNode.Value, out idx))
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Invalid array index {childNode.Name.LocalName} in XML node {parentNode.Name.LocalName} at line {((IXmlLineInfo)childNode).LineNumber}");
                        return;
                    }

                    if (idx >= 0)
                    {
                        T element = new T
                        {
                            Key = idx
                        };

                        ParseNode(basePath, childNode, element);

                        elements.Add(element);
                    }
                    else
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Invalid array index {childNode.Name.LocalName} in XML node {parentNode.Name.LocalName} at line {((IXmlLineInfo)indexNode).LineNumber}");
                    }
                }
            }
        }
Пример #8
0
 /// <summary>Parses an XML node containing a list of sounds into a car sound array</summary>
 /// <param name="node">The node to parse</param>
 /// <param name="Sounds">The car sound array</param>
 /// <param name="Position">The default position of the sound (May be overriden by any node)</param>
 /// <param name="Radius">The default radius of the sound (May be overriden by any node)</param>
 private static void ParseArrayNode(XmlNode node, out TrainManager.CarSound[] Sounds, Vector3 Position, double Radius)
 {
     Sounds = new TrainManager.CarSound[0];
     foreach (XmlNode c in node.ChildNodes)
     {
         int idx = -1;
         if (c.Name.ToLowerInvariant() != "sound")
         {
             Interface.AddMessage(Interface.MessageType.Error, false, "Invalid array node " + c.Name + " in XML node " + node.Name);
         }
         else
         {
             for (int i = 0; i < c.ChildNodes.Count; i++)
             {
                 if (c.ChildNodes[i].Name.ToLowerInvariant() == "index")
                 {
                     if (!NumberFormats.TryParseIntVb6(c.ChildNodes[i].InnerText.ToLowerInvariant(), out idx))
                     {
                         Interface.AddMessage(Interface.MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name);
                         return;
                     }
                     break;
                 }
             }
             if (idx >= 0)
             {
                 int l = Sounds.Length;
                 Array.Resize(ref Sounds, idx + 1);
                 while (l < Sounds.Length)
                 {
                     Sounds[l] = TrainManager.CarSound.Empty;
                     l++;
                 }
                 ParseNode(c, out Sounds[idx], Position, Radius);
             }
             else
             {
                 Interface.AddMessage(Interface.MessageType.Error, false, "Invalid array index " + c.Name + " in XML node " + node.Name);
             }
         }
     }
 }
Пример #9
0
        private static void ParseTouchSoundEntryNode(string fileName, XElement parent, ICollection <int> indices)
        {
            foreach (XElement childNode in parent.Elements())
            {
                if (childNode.Name.LocalName.ToLowerInvariant() != "entry")
                {
                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"Invalid entry node {childNode.Name.LocalName} in XML node {parent.Name.LocalName} at line {((IXmlLineInfo)childNode).LineNumber}");
                }
                else
                {
                    System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.InvariantCulture;

                    string section = childNode.Name.LocalName;

                    foreach (XElement keyNode in childNode.Elements())
                    {
                        string key        = keyNode.Name.LocalName;
                        string value      = keyNode.Value;
                        int    lineNumber = ((IXmlLineInfo)keyNode).LineNumber;

                        switch (keyNode.Name.LocalName.ToLowerInvariant())
                        {
                        case "index":
                            if (value.Any())
                            {
                                int index;

                                if (!NumberFormats.TryParseIntVb6(value, out index))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"value is invalid in {key} in {section} at line {lineNumber.ToString(culture)} in {fileName}");
                                }

                                indices.Add(index);
                            }
                            break;
                        }
                    }
                }
            }
        }
Пример #10
0
        /// <summary>Parses an XML node containing a list of sounds into a car sound array</summary>
        /// <param name="node">The node to parse</param>
        /// <param name="Sounds">The car sound array</param>
        /// <param name="Position">The default position of the sound (May be overriden by any node)</param>
        /// <param name="Radius">The default radius of the sound (May be overriden by any node)</param>
        private static void ParseArrayNode(XmlNode node, out CarSound[] Sounds, Vector3 Position, double Radius)
        {
            Sounds = new CarSound[0];

            foreach (XmlNode c in node.ChildNodes)
            {
                int idx = -1;
                if (c.Name.ToLowerInvariant() == "sound")
                {
                    for (int i = 0; i < c.ChildNodes.Count; i++)
                    {
                        if (c.ChildNodes[i].Name.ToLowerInvariant() == "index")
                        {
                            if (!NumberFormats.TryParseIntVb6(c.ChildNodes[i].InnerText.ToLowerInvariant(), out idx))
                            {
                                return;
                            }
                            break;
                        }
                    }

                    if (idx >= 0)
                    {
                        int l = Sounds.Length;
                        Array.Resize(ref Sounds, idx + 1);

                        while (l < Sounds.Length)
                        {
                            Sounds[l] = new CarSound();
                            l++;
                        }

                        ParseNode(c, out Sounds[idx], Position, Radius);
                    }
                }
            }
        }
Пример #11
0
        private void ParseRouteCommand(RouteCommand Command, string[] Arguments, int Index, string FileName, double[] UnitOfLength, Expression Expression, ref RouteData Data, bool PreviewOnly)
        {
            switch (Command)
            {
            case RouteCommand.DeveloperID:
                //Unused by OpenBVE
                break;

            case RouteCommand.Comment:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    CurrentRoute.Comment = Arguments[0];
                }

                break;

            case RouteCommand.Image:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    string f = Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), Arguments[0]);
                    if (!System.IO.File.Exists(f))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, true, "FileName " + f + " not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        CurrentRoute.Image = f;
                    }
                }

                break;

            case RouteCommand.TimeTable:
                if (!PreviewOnly)
                {
                    if (Arguments.Length < 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "" + Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        CurrentRoute.Information.DefaultTimetableDescription = Arguments[0];
                    }
                }

                break;

            case RouteCommand.Change:
                if (!PreviewOnly)
                {
                    int change = 0;
                    if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out change))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        change = 0;
                    }
                    else if (change < -1 | change > 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is expected to be -1, 0 or 1 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        change = 0;
                    }

                    Plugin.CurrentOptions.TrainStart = (TrainStartMode)change;
                }

                break;

            case RouteCommand.Gauge:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    double a;
                    if (!NumberFormats.TryParseDoubleVb6(Arguments[0], out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInMillimeters is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a <= 0.0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInMillimeters is expected to be positive in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        for (int tt = 0; tt < CurrentRoute.Tracks.Count; tt++)
                        {
                            int t = CurrentRoute.Tracks.ElementAt(tt).Key;
                            CurrentRoute.Tracks[t].RailGauge = 0.001 * a;
                        }
                    }
                }
                break;

            case RouteCommand.Signal:
                if (!PreviewOnly)
                {
                    if (Arguments.Length < 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        double a;
                        if (!NumberFormats.TryParseDoubleVb6(Arguments[0], out a))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Speed is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        }
                        else
                        {
                            if (Index < 0)
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "AspectIndex is expected to be non-negative in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            }
                            else if (a < 0.0)
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Speed is expected to be non-negative in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            }
                            else
                            {
                                if (Index >= Data.SignalSpeeds.Length)
                                {
                                    int n = Data.SignalSpeeds.Length;
                                    Array.Resize(ref Data.SignalSpeeds, Index + 1);
                                    for (int i = n; i < Index; i++)
                                    {
                                        Data.SignalSpeeds[i] = double.PositiveInfinity;
                                    }
                                }

                                Data.SignalSpeeds[Index] = a * Data.UnitOfSpeed;
                            }
                        }
                    }
                }
                break;

            case RouteCommand.AccelerationDueToGravity:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    double a;
                    if (!NumberFormats.TryParseDoubleVb6(Arguments[0], out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a <= 0.0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Value is expected to be positive in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        CurrentRoute.Atmosphere.AccelerationDueToGravity = a;
                    }
                }
                break;

            case RouteCommand.StartTime:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    double t;
                    if (!TryParseTime(Arguments[0], out t))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, Arguments[0] + " does not parse to a valid time in command " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        if (CurrentRoute.InitialStationTime == -1)
                        {
                            CurrentRoute.InitialStationTime = t;
                        }
                    }
                }
                break;

            case RouteCommand.LoadingScreen:
                if (PreviewOnly)
                {
                    return;
                }

                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    string f = Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), Arguments[0]);
                    if (!System.IO.File.Exists(f))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, true, "FileName " + f + " not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        Texture t = new Texture(f, new TextureParameters(null, null), Plugin.CurrentHost);
                        CurrentRoute.Information.LoadingScreenBackground = t;
                    }
                }

                break;

            case RouteCommand.DisplaySpeed:
                if (PreviewOnly)
                {
                    return;
                }

                if (Arguments.Length == 1 && Arguments[0].IndexOf(',') != -1)
                {
                    Arguments = Arguments[0].Split(',');
                }
                if (Arguments.Length != 2)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have two arguments at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    break;
                }
                Plugin.CurrentOptions.UnitOfSpeed = Arguments[0];
                if (!double.TryParse(Arguments[1], NumberStyles.Float, Culture, out Plugin.CurrentOptions.SpeedConversionFactor))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Speed conversion factor is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    Plugin.CurrentOptions.UnitOfSpeed = "km/h";
                }
                break;

            case RouteCommand.Briefing:
                if (PreviewOnly)
                {
                    return;
                }

                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    string f = Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), Arguments[0]);
                    if (!System.IO.File.Exists(f))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, true, "FileName " + f + " not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        CurrentRoute.Information.RouteBriefing = f;
                    }
                }
                break;

            case RouteCommand.Elevation:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    double a;
                    if (!NumberFormats.TryParseDoubleVb6(Arguments[0], UnitOfLength, out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Height is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        CurrentRoute.Atmosphere.InitialElevation = a;
                    }
                }
                break;

            case RouteCommand.Temperature:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    double a;
                    if (!NumberFormats.TryParseDoubleVb6(Arguments[0], out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInCelsius is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a <= -273.15)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInCelsius is expected to be greater than -273.15 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a >= 100.0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInCelsius is expected to be less than 100.0 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        CurrentRoute.Atmosphere.InitialAirTemperature = a + 273.15;
                    }
                }
                break;

            case RouteCommand.Pressure:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    double a;
                    if (!NumberFormats.TryParseDoubleVb6(Arguments[0], out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInKPa is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a <= 0.0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInKPa is expected to be positive in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a >= 120.0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ValueInKPa is expected to be less than 120.0 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        CurrentRoute.Atmosphere.InitialAirPressure = 1000.0 * a;
                    }
                }
                break;

            case RouteCommand.AmbientLight:
            {
                if (Plugin.CurrentRoute.DynamicLighting)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Dynamic lighting is enabled- Route.AmbientLight will be ignored");
                    break;
                }

                int r = 255, g = 255, b = 255;
                if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out r))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RedValue is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else if (r < 0 | r > 255)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RedValue is required to be within the range from 0 to 255 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    r = r < 0 ? 0 : 255;
                }

                if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[1], out g))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "GreenValue is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else if (g < 0 | g > 255)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "GreenValue is required to be within the range from 0 to 255 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    g = g < 0 ? 0 : 255;
                }

                if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[2], out b))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "BlueValue is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else if (b < 0 | b > 255)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "BlueValue is required to be within the range from 0 to 255 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    b = b < 0 ? 0 : 255;
                }

                Plugin.CurrentRoute.Atmosphere.AmbientLightColor = new Color24((byte)r, (byte)g, (byte)b);
            }
            break;

            case RouteCommand.DirectionalLight:
            {
                if (Plugin.CurrentRoute.DynamicLighting)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Dynamic lighting is enabled- Route.DirectionalLight will be ignored");
                    break;
                }

                int r = 255, g = 255, b = 255;
                if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out r))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RedValue is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else if (r < 0 | r > 255)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RedValue is required to be within the range from 0 to 255 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    r = r < 0 ? 0 : 255;
                }

                if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[1], out g))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "GreenValue is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else if (g < 0 | g > 255)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "GreenValue is required to be within the range from 0 to 255 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    g = g < 0 ? 0 : 255;
                }

                if (Arguments.Length >= 3 && Arguments[2].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[2], out b))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "BlueValue is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else if (b < 0 | b > 255)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "BlueValue is required to be within the range from 0 to 255 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    b = b < 0 ? 0 : 255;
                }

                Plugin.CurrentRoute.Atmosphere.DiffuseLightColor = new Color24((byte)r, (byte)g, (byte)b);
            }
            break;

            case RouteCommand.LightDirection:
            {
                if (Plugin.CurrentRoute.DynamicLighting)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "Dynamic lighting is enabled- Route.LightDirection will be ignored");
                    break;
                }

                double theta = 60.0, phi = -26.565051177078;
                if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[0], out theta))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Theta is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }

                if (Arguments.Length >= 2 && Arguments[1].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[1], out phi))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Phi is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }

                theta = theta.ToRadians();
                phi   = phi.ToRadians();
                double dx = Math.Cos(theta) * Math.Sin(phi);
                double dy = -Math.Sin(theta);
                double dz = Math.Cos(theta) * Math.Cos(phi);
                Plugin.CurrentRoute.Atmosphere.LightPosition = new Vector3((float)-dx, (float)-dy, (float)-dz);
            }
            break;

            case RouteCommand.DynamicLight:
                //Read the lighting XML file
                string path = Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), Arguments[0]);
                if (System.IO.File.Exists(path))
                {
                    if (DynamicLightParser.ReadLightingXML(path, out Plugin.CurrentRoute.LightDefinitions))
                    {
                        Plugin.CurrentRoute.DynamicLighting = true;
                        Data.Structure.LightDefinitions.Add(int.MaxValue, Plugin.CurrentRoute.LightDefinitions);
                    }
                    else
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The file " + path + " is not a valid dynamic lighting XML file, at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                }
                else
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Dynamic lighting XML file not found at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                break;

            case RouteCommand.InitialViewPoint:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    int cv;
                    if (!NumberFormats.TryParseIntVb6(Arguments[0], out cv))
                    {
                        switch (Arguments[0].ToLowerInvariant())
                        {
                        case "cab":
                            cv = 0;
                            break;

                        case "exterior":
                            cv = 1;
                            break;

                        case "track":
                            cv = 2;
                            break;

                        case "flyby":
                            cv = 3;
                            break;

                        case "flybyzooming":
                            cv = 4;
                            break;

                        default:
                            cv = 0;
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is invalid at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            break;
                        }
                    }

                    if (cv >= 0 && cv <= 4)
                    {
                        Plugin.CurrentOptions.InitialViewpoint = cv;
                    }
                    else
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is invalid at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                }
                break;

            case RouteCommand.TfoXML:
                if (!PreviewOnly)
                {
                    string tfoFile = Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), Arguments[0]);
                    if (!System.IO.File.Exists(tfoFile))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, true, "TrackFollowingObject XML file " + tfoFile + " not found in Track.TfoXML at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        break;
                    }

                    if (Plugin.TrainManager.TFOs == null)
                    {
                        Plugin.TrainManager.TFOs = new AbstractTrain[] { };
                    }
                    int n = Plugin.TrainManager.TFOs.Length;
                    Array.Resize(ref Plugin.TrainManager.TFOs, n + 1);
                    Plugin.TrainManager.TFOs[n] = Plugin.CurrentHost.ParseTrackFollowingObject(ObjectPath, tfoFile);
                }
                break;
            }
        }
            internal void LoadCalibration(string calibrationFile)
            {
                if (!File.Exists(calibrationFile))
                {
                    return;
                }
                try
                {
                    for (int i = 0; i < Calibration.Length; i++)
                    {
                        Calibration[i] = new AxisCalibration();
                    }
                    XmlDocument currentXML = new XmlDocument();
                    currentXML.Load(calibrationFile);
                    XmlNodeList documentNodes = currentXML.SelectNodes("openBVE/RailDriverCalibration");
                    if (documentNodes != null && documentNodes.Count != 0)
                    {
                        for (int i = 0; i < documentNodes.Count; i++)
                        {
                            int idx  = -1;
                            int lMin = 0;
                            int lMax = 255;
                            foreach (XmlNode node in documentNodes[i].ChildNodes)
                            {
                                switch (node.Name.ToLowerInvariant())
                                {
                                case "axis":
                                    foreach (XmlNode n in node.ChildNodes)
                                    {
                                        switch (n.Name.ToLowerInvariant())
                                        {
                                        case "index":
                                            if (!NumberFormats.TryParseIntVb6(n.InnerText, out idx))
                                            {
                                                Program.AppendToLogFile(@"Invalid index in RailDriver calibration file");
                                            }
                                            break;

                                        case "minimum":
                                            if (!NumberFormats.TryParseIntVb6(n.InnerText, out lMin))
                                            {
                                                Program.AppendToLogFile(@"Invalid minimum in RailDriver calibration file");
                                            }
                                            break;

                                        case "maximum":
                                            if (!NumberFormats.TryParseIntVb6(n.InnerText, out lMax))
                                            {
                                                Program.AppendToLogFile(@"Invalid minimum in RailDriver calibration file");
                                            }
                                            break;
                                        }
                                    }
                                    lMin = Math.Abs(lMin);
                                    lMax = Math.Abs(lMax);
                                    if (lMin > 255)
                                    {
                                        lMin = 255;
                                    }
                                    else if (lMin < 0)
                                    {
                                        lMin = 0;
                                    }
                                    if (lMax >= 255)
                                    {
                                        lMax = 255;
                                    }
                                    else if (lMax < 0)
                                    {
                                        lMax = 0;
                                    }
                                    if (lMin >= lMax)
                                    {
                                        throw new InvalidDataException(@"Maximum must be non-zero and greater than minimum.");
                                    }
                                    if (idx == -1)
                                    {
                                        throw new InvalidDataException(@"Invalid axis specified.");
                                    }
                                    Calibration[idx].Minimum = lMin;
                                    Calibration[idx].Maximum = lMax;
                                    break;
                                }
                            }
                        }
                    }
                }
                catch
                {
                    for (int i = 0; i < Calibration.Length; i++)
                    {
                        Calibration[i] = new AxisCalibration();
                    }
                    MessageBox.Show(Interface.GetInterfaceString("raildriver_config_error"), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    //Clear the calibration file
                    File.Delete(calibrationFile);
                }
            }
        /// <summary>Preprocesses the options contained within a route file</summary>
        /// <param name="IsRW">Whether the current route file is in RW format</param>
        /// <param name="Expressions">The initial list of expressions</param>
        /// <param name="Data">The finalized route data</param>
        /// <param name="UnitOfLength">The units of length conversion factor to be applied</param>
        /// <param name="PreviewOnly">Whether this is a preview only</param>
        private static void PreprocessOptions(bool IsRW, Expression[] Expressions, ref RouteData Data, ref double[] UnitOfLength, bool PreviewOnly)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            string Section             = "";
            bool   SectionAlwaysPrefix = false;

            // process expressions
            for (int j = 0; j < Expressions.Length; j++)
            {
                if (IsRW && Expressions[j].Text.StartsWith("[") && Expressions[j].Text.EndsWith("]"))
                {
                    Section = Expressions[j].Text.Substring(1, Expressions[j].Text.Length - 2).Trim(new char[] { });
                    if (string.Compare(Section, "object", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        Section = "Structure";
                    }
                    else if (string.Compare(Section, "railway", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        Section = "Track";
                    }
                    SectionAlwaysPrefix = true;
                }
                else
                {
                    Expressions[j].ConvertRwToCsv(Section, SectionAlwaysPrefix);
                    // separate command and arguments
                    string Command, ArgumentSequence;
                    Expressions[j].SeparateCommandsAndArguments(out Command, out ArgumentSequence, Culture, true, IsRW, Section);
                    // process command
                    double Number;
                    bool   NumberCheck = !IsRW || string.Compare(Section, "track", StringComparison.OrdinalIgnoreCase) == 0;
                    if (!NumberCheck || !NumberFormats.TryParseDoubleVb6(Command, UnitOfLength, out Number))
                    {
                        // split arguments
                        string[] Arguments;
                        {
                            int n = 0;
                            for (int k = 0; k < ArgumentSequence.Length; k++)
                            {
                                if (IsRW & ArgumentSequence[k] == ',')
                                {
                                    n++;
                                }
                                else if (ArgumentSequence[k] == ';')
                                {
                                    n++;
                                }
                            }
                            Arguments = new string[n + 1];
                            int a = 0, h = 0;
                            for (int k = 0; k < ArgumentSequence.Length; k++)
                            {
                                if (IsRW & ArgumentSequence[k] == ',')
                                {
                                    Arguments[h] = ArgumentSequence.Substring(a, k - a).Trim(new char[] { });
                                    a            = k + 1; h++;
                                }
                                else if (ArgumentSequence[k] == ';')
                                {
                                    Arguments[h] = ArgumentSequence.Substring(a, k - a).Trim(new char[] { });
                                    a            = k + 1; h++;
                                }
                            }
                            if (ArgumentSequence.Length - a > 0)
                            {
                                Arguments[h] = ArgumentSequence.Substring(a).Trim(new char[] { });
                                h++;
                            }
                            Array.Resize <string>(ref Arguments, h);
                        }
                        // preprocess command
                        if (Command.ToLowerInvariant() == "with")
                        {
                            if (Arguments.Length >= 1)
                            {
                                Section             = Arguments[0];
                                SectionAlwaysPrefix = false;
                            }
                            else
                            {
                                Section             = "";
                                SectionAlwaysPrefix = false;
                            }
                            Command = null;
                        }
                        else
                        {
                            if (Command.StartsWith("."))
                            {
                                Command = Section + Command;
                            }
                            else if (SectionAlwaysPrefix)
                            {
                                Command = Section + "." + Command;
                            }
                            Command = Command.Replace(".Void", "");
                        }
                        // handle indices
                        if (Command != null && Command.EndsWith(")"))
                        {
                            for (int k = Command.Length - 2; k >= 0; k--)
                            {
                                if (Command[k] == '(')
                                {
                                    string Indices = Command.Substring(k + 1, Command.Length - k - 2).TrimStart(new char[] { });
                                    Command = Command.Substring(0, k).TrimEnd(new char[] { });
                                    int h = Indices.IndexOf(";", StringComparison.Ordinal);
                                    int CommandIndex1;
                                    if (h >= 0)
                                    {
                                        string a = Indices.Substring(0, h).TrimEnd(new char[] { });
                                        string b = Indices.Substring(h + 1).TrimStart(new char[] { });
                                        if (a.Length > 0 && !NumberFormats.TryParseIntVb6(a, out CommandIndex1))
                                        {
                                            Command = null; break;
                                        }
                                        int CommandIndex2;
                                        if (b.Length > 0 && !NumberFormats.TryParseIntVb6(b, out CommandIndex2))
                                        {
                                            Command = null;
                                        }
                                    }
                                    else
                                    {
                                        if (Indices.Length > 0 && !NumberFormats.TryParseIntVb6(Indices, out CommandIndex1))
                                        {
                                            Command = null;
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                        // process command
                        if (Command != null)
                        {
                            switch (Command.ToLowerInvariant())
                            {
                            // options
                            case "options.unitoflength":
                            {
                                if (Arguments.Length == 0)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "At least 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                }
                                else
                                {
                                    UnitOfLength = new double[Arguments.Length];
                                    for (int i = 0; i < Arguments.Length; i++)
                                    {
                                        UnitOfLength[i] = i == Arguments.Length - 1 ? 1.0 : 0.0;
                                        if (Arguments[i].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[i], out UnitOfLength[i]))
                                        {
                                            Interface.AddMessage(MessageType.Error, false, "FactorInMeters" + i.ToString(Culture) + " is invalid in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                            UnitOfLength[i] = i == 0 ? 1.0 : 0.0;
                                        }
                                        else if (UnitOfLength[i] <= 0.0)
                                        {
                                            Interface.AddMessage(MessageType.Error, false, "FactorInMeters" + i.ToString(Culture) + " is expected to be positive in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                            UnitOfLength[i] = i == Arguments.Length - 1 ? 1.0 : 0.0;
                                        }
                                    }
                                }
                            }
                            break;

                            case "options.unitofspeed":
                            {
                                if (Arguments.Length < 1)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                }
                                else
                                {
                                    if (Arguments.Length > 1)
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                    }
                                    if (Arguments[0].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[0], out Data.UnitOfSpeed))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "FactorInKmph is invalid in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        Data.UnitOfSpeed = 0.277777777777778;
                                    }
                                    else if (Data.UnitOfSpeed <= 0.0)
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "FactorInKmph is expected to be positive in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        Data.UnitOfSpeed = 0.277777777777778;
                                    }
                                    else
                                    {
                                        Data.UnitOfSpeed *= 0.277777777777778;
                                    }
                                }
                            }
                            break;

                            case "options.objectvisibility":
                            {
                                if (Arguments.Length == 0)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                }
                                else
                                {
                                    if (Arguments.Length > 1)
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                    }
                                    int mode = 0;
                                    if (Arguments.Length >= 1 && Arguments[0].Length != 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out mode))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Mode is invalid in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        mode = 0;
                                    }
                                    else if (mode != 0 & mode != 1)
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The specified Mode is not supported in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        mode = 0;
                                    }
                                    Data.AccurateObjectDisposal = mode == 1;
                                }
                            }
                            break;

                            case "options.compatibletransparencymode":
                            {
                                //Whether to use fuzzy matching for BVE2 / BVE4 transparencies
                                //Should be DISABLED on openBVE content
                                if (PreviewOnly)
                                {
                                    continue;
                                }
                                if (Arguments.Length == 0)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                }
                                else
                                {
                                    if (Arguments.Length > 1)
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                    }
                                    int mode = 0;
                                    if (Arguments.Length >= 1 && Arguments[0].Length != 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out mode))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Mode is invalid in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        mode = 0;
                                    }
                                    else if (mode != 0 & mode != 1)
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The specified Mode is not supported in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        mode = 0;
                                    }
                                    Interface.CurrentOptions.OldTransparencyMode = mode == 1;
                                }
                            }
                            break;

                            case "options.enablehacks":
                            {
                                //Whether to apply various hacks to fix BVE2 / BVE4 routes
                                //Whilst this is harmless, it should be DISABLED on openBVE content
                                //in order to ensure that all errors are correctly fixed by the developer
                                if (PreviewOnly)
                                {
                                    continue;
                                }
                                if (Arguments.Length == 0)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                }
                                else
                                {
                                    if (Arguments.Length > 1)
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Exactly 1 argument is expected in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                    }
                                    int mode = 0;
                                    if (Arguments.Length >= 1 && Arguments[0].Length != 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out mode))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Mode is invalid in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        mode = 0;
                                    }
                                    else if (mode != 0 & mode != 1)
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "The specified Mode is not supported in " + Command + " at line " + Expressions[j].Line.ToString(Culture) + ", column " + Expressions[j].Column.ToString(Culture) + " in file " + Expressions[j].File);
                                        mode = 0;
                                    }
                                    Interface.CurrentOptions.EnableBveTsHacks = mode == 1;
                                }
                            }
                            break;
                            }
                        }
                    }
                }
            }
        }
Пример #14
0
        internal static void Process(MainForm form)
        {
            mainForm = form;

            if (!System.IO.File.Exists(FileName))
            {
                MessageBox.Show("The selected folder does not contain a valid train.dat \r\n Please retry.", "CarXML Convertor", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            string[] Lines = System.IO.File.ReadAllLines(FileName);
            for (int i = 0; i < Lines.Length; i++)

            {
                int n = 0;
                switch (Lines[i].ToLowerInvariant())
                {
                case "#cockpit":
                case "#cab":
                    i++; while (i < Lines.Length && !Lines[i].StartsWith("#", StringComparison.Ordinal))
                    {
                        double a; if (NumberFormats.TryParseDoubleVb6(Lines[i], out a))
                        {
                            switch (n)
                            {
                            case 0: ConvertSoundCfg.DriverPosition.X = 0.001 * a; break;

                            case 1: ConvertSoundCfg.DriverPosition.Y = 0.001 * a; break;

                            case 2: ConvertSoundCfg.DriverPosition.Z = 0.001 * a; break;

                            case 3: DriverCar = (int)Math.Round(a); break;
                            }
                        }
                        i++; n++;
                    }
                    i--; break;

                case "#car":
                    i++; while (i < Lines.Length && !Lines[i].StartsWith("#", StringComparison.Ordinal))
                    {
                        double a; if (NumberFormats.TryParseDoubleVb6(Lines[i], out a))
                        {
                            switch (n)
                            {
                            case 0:
                                if (!(a <= 0.0))
                                {
                                    MotorCarMass = a * 1000.0;
                                }
                                break;

                            case 1:
                                if (!(a <= 0.0))
                                {
                                    NumberOfMotorCars = (int)Math.Round(a);
                                }
                                break;

                            case 2:
                                if (!(a <= 0.0))
                                {
                                    TrailerCarMass = a * 1000.0;
                                }
                                break;

                            case 3:
                                if (!(a <= 0.0))
                                {
                                    NumberOfTrailerCars = (int)Math.Round(a);
                                }
                                break;

                            case 4:
                                if (!(a <= 0.0))
                                {
                                    CarLength = a;
                                }
                                break;

                            case 5:
                                FrontCarIsMotorCar = a == 1.0;
                                break;

                            case 6:
                                if (!(a <= 0.0))
                                {
                                    CarWidth = a;
                                }
                                break;

                            case 7:
                                if (!(a <= 0.0))
                                {
                                    CarHeight = a;
                                }
                                break;
                            }
                        }
                        i++; n++;
                    }
                    i--; break;

                case "#brake":
                    i++; while (i < Lines.Length && !Lines[i].StartsWith("#", StringComparison.Ordinal))
                    {
                        int a; if (NumberFormats.TryParseIntVb6(Lines[i], out a))
                        {
                            switch (n)
                            {
                            case 0: BrakeType = a; break;
                            }
                        }
                        i++; n++;
                    }
                    i--; break;

                case "#move":
                    i++; while (i < Lines.Length && !Lines[i].StartsWith("#", StringComparison.Ordinal))
                    {
                        double a; if (NumberFormats.TryParseDoubleVb6(Lines[i], out a))
                        {
                            switch (n)
                            {
                            case 4: BrakeCylinderEmergencyRate = a * 1000.0; break;

                            case 5: BrakeCylinderReleaseRate = a * 1000.0; break;
                            }
                        }
                        i++; n++;
                    }
                    i--; break;

                case "#pressure":
                    i++; while (i < Lines.Length && !Lines[i].StartsWith("#", StringComparison.Ordinal))
                    {
                        double a; if (NumberFormats.TryParseDoubleVb6(Lines[i], out a))
                        {
                            switch (n)
                            {
                            case 0:
                                if (a <= 0.0)
                                {
                                    mainForm.updateLogBoxText += "BrakeCylinderServiceMaximumPressure is expected to be positive at line " + (i + 1).ToString(CultureInfo.InvariantCulture) + " in " + FileName;
                                }
                                else
                                {
                                    BrakeCylinderServiceMaximumPressure = a * 1000.0;
                                } break;

                            case 1:
                                if (a <= 0.0)
                                {
                                    mainForm.updateLogBoxText += "BrakeCylinderEmergencyMaximumPressure is expected to be positive at line " + (i + 1).ToString(CultureInfo.InvariantCulture) + " in " + FileName;
                                }
                                else
                                {
                                    BrakeCylinderEmergencyMaximumPressure = a * 1000.0;
                                } break;

                            case 2:
                                if (a <= 0.0)
                                {
                                    mainForm.updateLogBoxText += "MainReservoirMinimumPressure is expected to be positive at line " + (i + 1).ToString(CultureInfo.InvariantCulture) + " in " + FileName;
                                }
                                else
                                {
                                    MainReservoirMinimumPressure = a * 1000.0;
                                } break;

                            case 3:
                                if (a <= 0.0)
                                {
                                    mainForm.updateLogBoxText += "MainReservoirMaximumPressure is expected to be positive at line " + (i + 1).ToString(CultureInfo.InvariantCulture) + " in " + FileName;
                                }
                                else
                                {
                                    MainReservoirMaximumPressure = a * 1000.0;
                                } break;

                            case 4:
                                if (a <= 0.0)
                                {
                                    mainForm.updateLogBoxText += "BrakePipePressue is expected to be positive at line " + (i + 1).ToString(CultureInfo.InvariantCulture) + " in " + FileName;
                                }
                                else
                                {
                                    BrakePipePressure = a * 1000.0;
                                } break;
                            }
                        }
                        i++; n++;
                    }
                    i--; break;

                default:
                {
                    i++;
                    while (i < Lines.Length && !Lines[i].StartsWith("#", StringComparison.Ordinal))
                    {
                        i++; n++;
                    }
                    i--;
                }
                break;
                }
            }

            if (BrakePipePressure <= 0.0)
            {
                if (BrakeType == 2)                 //Automatic air brake
                {
                    BrakePipePressure = BrakeCylinderEmergencyMaximumPressure + 0.75 * (MainReservoirMinimumPressure - BrakeCylinderEmergencyMaximumPressure);
                    if (BrakePipePressure > MainReservoirMinimumPressure)
                    {
                        BrakePipePressure = MainReservoirMinimumPressure;
                    }
                }
                else
                {
                    if (BrakeCylinderEmergencyMaximumPressure <480000.0& MainReservoirMinimumPressure> 500000.0)
                    {
                        BrakePipePressure = 490000.0;
                    }
                    else
                    {
                        BrakePipePressure = BrakeCylinderEmergencyMaximumPressure + 0.75 * (MainReservoirMinimumPressure - BrakeCylinderEmergencyMaximumPressure);
                    }
                }
            }

            NumberOfCars = NumberOfMotorCars + NumberOfTrailerCars;
            MotorCars    = new bool[NumberOfCars];
            if (NumberOfMotorCars == 1)
            {
                if (FrontCarIsMotorCar | NumberOfTrailerCars == 0)
                {
                    MotorCars[0] = true;
                }
                else
                {
                    MotorCars[NumberOfCars - 1] = true;
                }
            }
            else if (NumberOfMotorCars == 2)
            {
                if (FrontCarIsMotorCar | NumberOfTrailerCars == 0)
                {
                    MotorCars[0] = true;
                    MotorCars[NumberOfCars - 1] = true;
                }
                else if (NumberOfTrailerCars == 1)
                {
                    MotorCars[1] = true;
                    MotorCars[2] = true;
                }
                else
                {
                    int i = (int)Math.Ceiling(0.25 * (double)(NumberOfCars - 1));
                    int j = (int)Math.Floor(0.75 * (double)(NumberOfCars - 1));
                    MotorCars[i] = true;
                    MotorCars[j] = true;
                }
            }
            else if (NumberOfMotorCars > 0)
            {
                if (FrontCarIsMotorCar)
                {
                    MotorCars[0] = true;
                    double t = 1.0 + (double)NumberOfTrailerCars / (double)(NumberOfMotorCars - 1);
                    double r = 0.0;
                    double x = 0.0;
                    while (true)
                    {
                        double y = x + t - r;
                        x = Math.Ceiling(y);
                        r = x - y;
                        int i = (int)x;
                        if (i >= NumberOfCars)
                        {
                            break;
                        }
                        MotorCars[i] = true;
                    }
                }
                else
                {
                    MotorCars[1] = true;
                    double t = 1.0 + (double)(NumberOfTrailerCars - 1) / (double)(NumberOfMotorCars - 1);
                    double r = 0.0;
                    double x = 1.0;
                    while (true)
                    {
                        double y = x + t - r;
                        x = Math.Ceiling(y);
                        r = x - y;
                        int i = (int)x;
                        if (i >= NumberOfCars)
                        {
                            break;
                        }
                        MotorCars[i] = true;
                    }
                }
            }
        }
Пример #15
0
        public static Game.Station ReadStationXML(string fileName, bool PreviewOnly, Textures.Texture[] daytimeTimetableTextures, Textures.Texture[] nighttimeTimetableTextures, int CurrentStation, ref bool passAlarm, ref CsvRwRouteParser.StopRequest stopRequest)
        {
            Game.Station station = new Game.Station
            {
                Stops = new Game.StationStop[] { }
            };
            stopRequest.Early              = new TrackManager.RequestStop();
            stopRequest.OnTime             = new TrackManager.RequestStop();
            stopRequest.Late               = new TrackManager.RequestStop();
            stopRequest.OnTime.Probability = 75;
            //The current XML file to load
            XmlDocument currentXML = new XmlDocument();

            //Load the object's XML file
            currentXML.Load(fileName);
            string Path = System.IO.Path.GetDirectoryName(fileName);

            //Check for null
            if (currentXML.DocumentElement != null)
            {
                XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/Station");
                //Check this file actually contains OpenBVE light definition nodes
                if (DocumentNodes != null)
                {
                    foreach (XmlNode n in DocumentNodes)
                    {
                        if (n.ChildNodes.OfType <XmlElement>().Any())
                        {
                            foreach (XmlNode c in n.ChildNodes)
                            {
                                //string[] Arguments = c.InnerText.Split(',');
                                switch (c.Name.ToLowerInvariant())
                                {
                                case "name":
                                    if (!string.IsNullOrEmpty(c.InnerText))
                                    {
                                        station.Name = c.InnerText;
                                    }
                                    else
                                    {
                                        Interface.AddMessage(Interface.MessageType.Error, false, "Station name was empty in XML file " + fileName);
                                    }
                                    break;

                                case "arrivaltime":
                                    if (!string.IsNullOrEmpty(c.InnerText))
                                    {
                                        if (!Interface.TryParseTime(c.InnerText, out station.ArrivalTime))
                                        {
                                            Interface.AddMessage(Interface.MessageType.Error, false, "Station arrival time was invalid in XML file " + fileName);
                                        }
                                    }
                                    break;

                                case "departuretime":
                                    if (!string.IsNullOrEmpty(c.InnerText))
                                    {
                                        if (!Interface.TryParseTime(c.InnerText, out station.DepartureTime))
                                        {
                                            Interface.AddMessage(Interface.MessageType.Error, false, "Station arrival time was invalid in XML file " + fileName);
                                        }
                                    }
                                    break;

                                case "type":
                                    switch (c.InnerText.ToLowerInvariant())
                                    {
                                    case "c":
                                    case "changeends":
                                        station.Type = StationType.ChangeEnds;
                                        break;

                                    case "t":
                                    case "terminal":
                                        station.Type = StationType.Terminal;
                                        break;

                                    default:
                                        station.Type = StationType.Normal;
                                        break;
                                    }
                                    break;

                                case "passalarm":
                                    if (!string.IsNullOrEmpty(c.InnerText))
                                    {
                                        if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true")
                                        {
                                            passAlarm = true;
                                        }
                                        else
                                        {
                                            passAlarm = false;
                                        }
                                    }
                                    break;

                                case "doors":
                                    int  door     = 0;
                                    bool doorboth = false;
                                    if (!string.IsNullOrEmpty(c.InnerText))
                                    {
                                        switch (c.InnerText.ToLowerInvariant())
                                        {
                                        case "l":
                                        case "left":
                                            door = -1;
                                            break;

                                        case "r":
                                        case "right":
                                            door = 1;
                                            break;

                                        case "n":
                                        case "none":
                                        case "neither":
                                            door = 0;
                                            break;

                                        case "b":
                                        case "both":
                                            doorboth = true;
                                            break;

                                        default:
                                            if (!NumberFormats.TryParseIntVb6(c.InnerText, out door))
                                            {
                                                Interface.AddMessage(Interface.MessageType.Error, false, "Door side was invalid in XML file " + fileName);
                                                door = 0;
                                            }
                                            break;
                                        }
                                    }
                                    station.OpenLeftDoors  = door < 0.0 | doorboth;
                                    station.OpenRightDoors = door > 0.0 | doorboth;
                                    break;

                                case "forcedredsignal":
                                    if (!string.IsNullOrEmpty(c.InnerText))
                                    {
                                        if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true")
                                        {
                                            station.ForceStopSignal = true;
                                        }
                                        else
                                        {
                                            station.ForceStopSignal = false;
                                        }
                                    }
                                    break;

                                case "system":
                                    switch (c.InnerText.ToLowerInvariant())
                                    {
                                    case "0":
                                    case "ATS":
                                        station.SafetySystem = Game.SafetySystem.Ats;
                                        break;

                                    case "1":
                                    case "ATC":
                                        station.SafetySystem = Game.SafetySystem.Atc;
                                        break;

                                    default:
                                        Interface.AddMessage(Interface.MessageType.Error, false, "An invalid station safety system was specified in XML file " + fileName);
                                        station.SafetySystem = Game.SafetySystem.Ats;
                                        break;
                                    }
                                    break;

                                case "arrivalsound":
                                    string arrSound  = string.Empty;
                                    double arrRadius = 30.0;
                                    if (!c.ChildNodes.OfType <XmlElement>().Any())
                                    {
                                        foreach (XmlNode cc in c.ChildNodes)
                                        {
                                            switch (c.Name.ToLowerInvariant())
                                            {
                                            case "filename":
                                                try
                                                {
                                                    arrSound = OpenBveApi.Path.CombineFile(Path, cc.InnerText);
                                                }
                                                catch
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound filename is invalid in XML file " + fileName);
                                                }
                                                break;

                                            case "radius":
                                                if (!double.TryParse(cc.InnerText, out arrRadius))
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound radius was invalid in XML file " + fileName);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        try
                                        {
                                            arrSound = OpenBveApi.Path.CombineFile(Path, c.InnerText);
                                        }
                                        catch
                                        {
                                            Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound filename is invalid in XML file " + fileName);
                                        }
                                    }
                                    if (File.Exists(arrSound))
                                    {
                                        station.ArrivalSoundBuffer = Sounds.RegisterBuffer(arrSound, arrRadius);
                                    }
                                    else
                                    {
                                        Interface.AddMessage(Interface.MessageType.Error, false, "Arrival sound file does not exist in XML file " + fileName);
                                    }
                                    break;

                                case "stopduration":
                                    double stopDuration;
                                    if (!double.TryParse(c.InnerText, out stopDuration))
                                    {
                                        Interface.AddMessage(Interface.MessageType.Error, false, "Stop duration is invalid in XML file " + fileName);
                                    }
                                    else
                                    {
                                        if (stopDuration < 5.0)
                                        {
                                            stopDuration = 5.0;
                                        }
                                        station.StopTime = stopDuration;
                                    }
                                    break;

                                case "passengerratio":
                                    double ratio;
                                    if (!double.TryParse(c.InnerText, out ratio))
                                    {
                                        Interface.AddMessage(Interface.MessageType.Error, false, "Passenger ratio is invalid in XML file " + fileName);
                                    }
                                    else
                                    {
                                        if (ratio < 0.0)
                                        {
                                            Interface.AddMessage(Interface.MessageType.Error, false, "Passenger ratio must be non-negative in XML file " + fileName);
                                            ratio = 100.0;
                                        }
                                        station.PassengerRatio = ratio * 0.01;
                                    }
                                    break;

                                case "departuresound":
                                    string depSound  = string.Empty;
                                    double depRadius = 30.0;
                                    if (!c.ChildNodes.OfType <XmlElement>().Any())
                                    {
                                        foreach (XmlNode cc in c.ChildNodes)
                                        {
                                            switch (c.Name.ToLowerInvariant())
                                            {
                                            case "filename":
                                                try
                                                {
                                                    depSound = OpenBveApi.Path.CombineFile(Path, cc.InnerText);
                                                }
                                                catch
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound filename is invalid in XML file " + fileName);
                                                }
                                                break;

                                            case "radius":
                                                if (!double.TryParse(cc.InnerText, out depRadius))
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound radius was invalid in XML file " + fileName);
                                                }
                                                break;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        try
                                        {
                                            depSound = OpenBveApi.Path.CombineFile(Path, c.InnerText);
                                        }
                                        catch
                                        {
                                            Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound filename is invalid in XML file " + fileName);
                                        }
                                    }
                                    if (File.Exists(depSound))
                                    {
                                        station.DepartureSoundBuffer = Sounds.RegisterBuffer(depSound, depRadius);
                                    }
                                    else
                                    {
                                        Interface.AddMessage(Interface.MessageType.Error, false, "Departure sound file does not exist in XML file " + fileName);
                                    }
                                    break;

                                case "timetableindex":
                                    if (!PreviewOnly)
                                    {
                                        int ttidx = -1;
                                        if (!string.IsNullOrEmpty(c.InnerText))
                                        {
                                            if (NumberFormats.TryParseIntVb6(c.InnerText, out ttidx))
                                            {
                                                if (ttidx < 0)
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Timetable index must be non-negative in XML file " + fileName);
                                                    ttidx = -1;
                                                }
                                                else if (ttidx >= daytimeTimetableTextures.Length & ttidx >= nighttimeTimetableTextures.Length)
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Timetable index references a non-loaded texture in XML file " + fileName);
                                                    ttidx = -1;
                                                }
                                                station.TimetableDaytimeTexture   = ttidx >= 0 & ttidx < daytimeTimetableTextures.Length ? daytimeTimetableTextures[ttidx] : null;
                                                station.TimetableNighttimeTexture = ttidx >= 0 & ttidx < nighttimeTimetableTextures.Length ? nighttimeTimetableTextures[ttidx] : null;
                                                break;
                                            }
                                        }
                                        if (ttidx == -1)
                                        {
                                            if (CurrentStation > 0)
                                            {
                                                station.TimetableDaytimeTexture   = Game.Stations[CurrentStation - 1].TimetableDaytimeTexture;
                                                station.TimetableNighttimeTexture = Game.Stations[CurrentStation - 1].TimetableNighttimeTexture;
                                            }
                                            else if (daytimeTimetableTextures.Length > 0 & nighttimeTimetableTextures.Length > 0)
                                            {
                                                station.TimetableDaytimeTexture   = daytimeTimetableTextures[0];
                                                station.TimetableNighttimeTexture = nighttimeTimetableTextures[0];
                                            }
                                        }
                                    }
                                    break;

                                case "requeststop":
                                    station.Type     = StationType.RequestStop;
                                    station.StopMode = StationStopMode.AllRequestStop;
                                    foreach (XmlNode cc in c.ChildNodes)
                                    {
                                        switch (cc.Name.ToLowerInvariant())
                                        {
                                        case "aibehaviour":
                                            switch (cc.InnerText.ToLowerInvariant())
                                            {
                                            case "fullspeed":
                                            case "0":
                                                //With this set, the AI driver will not attempt to brake, but pass through at linespeed
                                                stopRequest.FullSpeed = true;
                                                break;

                                            case "normalbrake":
                                            case "1":
                                                //With this set, the AI driver breaks to a near stop whilst passing through the station
                                                stopRequest.FullSpeed = false;
                                                break;
                                            }
                                            break;

                                        case "playeronly":
                                            station.StopMode = StationStopMode.PlayerRequestStop;
                                            break;

                                        case "distance":
                                            if (!string.IsNullOrEmpty(cc.InnerText))
                                            {
                                                double d;
                                                if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out d))
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Request stop distance is invalid in XML file " + fileName);
                                                    break;
                                                }
                                                stopRequest.TrackPosition -= Math.Abs(d);
                                            }
                                            break;

                                        case "earlytime":
                                            if (!string.IsNullOrEmpty(cc.InnerText))
                                            {
                                                if (!Interface.TryParseTime(cc.InnerText, out stopRequest.Early.Time))
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Request stop early time was invalid in XML file " + fileName);
                                                }
                                            }
                                            break;

                                        case "latetime":
                                            if (!string.IsNullOrEmpty(cc.InnerText))
                                            {
                                                if (!Interface.TryParseTime(cc.InnerText, out stopRequest.Late.Time))
                                                {
                                                    Interface.AddMessage(Interface.MessageType.Error, false, "Request stop late time was invalid in XML file " + fileName);
                                                }
                                            }
                                            break;

                                        case "stopmessage":
                                            if (cc.ChildNodes.OfType <XmlElement>().Any())
                                            {
                                                foreach (XmlNode cd in cc.ChildNodes)
                                                {
                                                    switch (cd.Name.ToLowerInvariant())
                                                    {
                                                    case "early":
                                                        if (!string.IsNullOrEmpty(cd.InnerText))
                                                        {
                                                            stopRequest.Early.StopMessage = cd.InnerText;
                                                        }
                                                        break;

                                                    case "ontime":
                                                        if (!string.IsNullOrEmpty(cd.InnerText))
                                                        {
                                                            stopRequest.OnTime.StopMessage = cd.InnerText;
                                                        }
                                                        break;

                                                    case "late":
                                                        if (!string.IsNullOrEmpty(cd.InnerText))
                                                        {
                                                            stopRequest.Late.StopMessage = cd.InnerText;
                                                        }
                                                        break;

                                                    case "#text":
                                                        stopRequest.Early.StopMessage  = cc.InnerText;
                                                        stopRequest.OnTime.StopMessage = cc.InnerText;
                                                        stopRequest.Late.StopMessage   = cc.InnerText;
                                                        break;
                                                    }
                                                }
                                            }
                                            break;

                                        case "passmessage":
                                            if (cc.ChildNodes.OfType <XmlElement>().Any())
                                            {
                                                foreach (XmlNode cd in cc.ChildNodes)
                                                {
                                                    switch (cd.Name.ToLowerInvariant())
                                                    {
                                                    case "early":
                                                        if (!string.IsNullOrEmpty(cd.InnerText))
                                                        {
                                                            stopRequest.Early.PassMessage = cd.InnerText;
                                                        }
                                                        break;

                                                    case "ontime":
                                                        if (!string.IsNullOrEmpty(cd.InnerText))
                                                        {
                                                            stopRequest.OnTime.PassMessage = cd.InnerText;
                                                        }
                                                        break;

                                                    case "late":
                                                        if (!string.IsNullOrEmpty(cd.InnerText))
                                                        {
                                                            stopRequest.Late.PassMessage = cd.InnerText;
                                                        }
                                                        break;

                                                    case "#text":
                                                        stopRequest.Early.PassMessage  = cc.InnerText;
                                                        stopRequest.OnTime.PassMessage = cc.InnerText;
                                                        stopRequest.Late.PassMessage   = cc.InnerText;
                                                        break;
                                                    }
                                                }
                                            }
                                            break;

                                        case "probability":
                                            foreach (XmlNode cd in cc.ChildNodes)
                                            {
                                                switch (cd.Name.ToLowerInvariant())
                                                {
                                                case "early":
                                                    if (!string.IsNullOrEmpty(cd.InnerText))
                                                    {
                                                        if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.Early.Probability))
                                                        {
                                                            Interface.AddMessage(Interface.MessageType.Error, false, "Request stop early probability was invalid in XML file " + fileName);
                                                        }
                                                    }
                                                    break;

                                                case "ontime":
                                                    if (!string.IsNullOrEmpty(cd.InnerText))
                                                    {
                                                        if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability))
                                                        {
                                                            Interface.AddMessage(Interface.MessageType.Error, false, "Request stop ontime probability was invalid in XML file " + fileName);
                                                        }
                                                    }
                                                    break;

                                                case "late":
                                                    if (!string.IsNullOrEmpty(cd.InnerText))
                                                    {
                                                        if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability))
                                                        {
                                                            Interface.AddMessage(Interface.MessageType.Error, false, "Request stop late probability was invalid in XML file " + fileName);
                                                        }
                                                    }
                                                    break;

                                                case "#text":
                                                    if (!NumberFormats.TryParseIntVb6(cd.InnerText, out stopRequest.OnTime.Probability))
                                                    {
                                                        Interface.AddMessage(Interface.MessageType.Error, false, "Request stop probability was invalid in XML file " + fileName);
                                                    }
                                                    break;
                                                }
                                            }

                                            break;

                                        case "maxcars":
                                            if (!NumberFormats.TryParseIntVb6(cc.InnerText, out stopRequest.MaxNumberOfCars))
                                            {
                                                Interface.AddMessage(Interface.MessageType.Error, false, "Request stop maximum cars was invalid in XML file " + fileName);
                                            }
                                            break;
                                        }
                                    }

                                    break;
                                }
                            }
                        }
                    }
                    return(station);
                }
            }
            //We couldn't find any valid XML, so return false
            throw new InvalidDataException();
        }
Пример #16
0
        private void ParseOptionCommand(OptionsCommand Command, string[] Arguments, double[] UnitOfLength, Expression Expression, ref RouteData Data, bool PreviewOnly)
        {
            switch (Command)
            {
            case OptionsCommand.BlockLength:
            {
                double length = 25.0;
                if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[0], UnitOfLength, out length))
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Length is invalid in Options.BlockLength at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    length = 25.0;
                }

                Data.BlockInterval = length;
            }
            break;

            case OptionsCommand.XParser:
                if (!PreviewOnly)
                {
                    int parser = 0;
                    if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out parser) | parser < 0 | parser > 3)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "XParser is invalid in Options.XParser at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        for (int i = 0; i < Plugin.CurrentHost.Plugins.Length; i++)
                        {
                            if (Plugin.CurrentHost.Plugins[i].Object != null)
                            {
                                Plugin.CurrentHost.Plugins[i].Object.SetObjectParser((XParsers)parser);                                          //Remember that this will be ignored if not the X plugin!
                            }
                        }
                    }
                }

                break;

            case OptionsCommand.ObjParser:
                if (!PreviewOnly)
                {
                    int parser = 0;
                    if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out parser) | parser < 0 | parser > 2)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "ObjParser is invalid in Options.ObjParser at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        for (int i = 0; i < Plugin.CurrentHost.Plugins.Length; i++)
                        {
                            if (Plugin.CurrentHost.Plugins[i].Object != null)
                            {
                                Plugin.CurrentHost.Plugins[i].Object.SetObjectParser((ObjParsers)parser);                                          //Remember that this will be ignored if not the Obj plugin!
                            }
                        }
                    }
                }

                break;

            case OptionsCommand.UnitOfLength:
            case OptionsCommand.UnitOfSpeed:
            case OptionsCommand.ObjectVisibility:
                break;

            case OptionsCommand.SectionBehavior:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    int a;
                    if (!NumberFormats.TryParseIntVb6(Arguments[0], out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a != 0 & a != 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is expected to be either 0 or 1 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        Data.ValueBasedSections = a == 1;
                    }
                }

                break;

            case OptionsCommand.CantBehavior:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    int a;
                    if (!NumberFormats.TryParseIntVb6(Arguments[0], out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a != 0 & a != 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is expected to be either 0 or 1 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        Data.SignedCant = a == 1;
                    }
                }

                break;

            case OptionsCommand.FogBehavior:
                if (Arguments.Length < 1)
                {
                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                }
                else
                {
                    int a;
                    if (!NumberFormats.TryParseIntVb6(Arguments[0], out a))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (a != 0 & a != 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Mode is expected to be either 0 or 1 in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        Data.FogTransitionMode = a == 1;
                    }
                }
                break;
            }
        }
Пример #17
0
        internal static void ParsePatchNode(XmlNode node, ref Dictionary <string, RoutefilePatch> routeFixes)
        {
            RoutefilePatch currentPatch = new RoutefilePatch();
            string         currentHash  = string.Empty;

            foreach (XmlElement childNode in node.ChildNodes.OfType <XmlElement>())
            {
                string t;
                switch (childNode.Name)
                {
                case "Hash":
                    currentHash = childNode.InnerText;
                    break;

                case "FileName":
                    currentPatch.FileName = childNode.InnerText;
                    break;

                case "LineEndingFix":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.LineEndingFix = true;
                    }
                    else
                    {
                        currentPatch.LineEndingFix = false;
                    }
                    break;

                case "IgnorePitchRoll":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.IgnorePitchRoll = true;
                    }
                    else
                    {
                        currentPatch.IgnorePitchRoll = false;
                    }
                    break;

                case "LogMessage":
                    currentPatch.LogMessage = childNode.InnerText;
                    break;

                case "CylinderHack":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.CylinderHack = true;
                    }
                    else
                    {
                        currentPatch.CylinderHack = false;
                    }
                    break;

                case "Expression":
                    t = childNode.Attributes["Number"].InnerText;
                    int expressionNumber;
                    if (NumberFormats.TryParseIntVb6(t, out expressionNumber))
                    {
                        currentPatch.ExpressionFixes.Add(expressionNumber, childNode.InnerText);
                    }
                    break;

                case "XParser":
                    switch (childNode.InnerText.ToLowerInvariant())
                    {
                    case "original":
                        currentPatch.XParser = XParsers.Original;
                        break;

                    case "new":
                        currentPatch.XParser = XParsers.NewXParser;
                        break;

                    case "assimp":
                        currentPatch.XParser = XParsers.Assimp;
                        break;
                    }
                    break;

                case "DummyRailTypes":
                    string[] splitString = childNode.InnerText.Split(',');
                    for (int i = 0; i < splitString.Length; i++)
                    {
                        int rt;
                        if (NumberFormats.TryParseIntVb6(splitString[i], out rt))
                        {
                            currentPatch.DummyRailTypes.Add(rt);
                        }
                    }
                    break;

                case "DummyGroundTypes":
                    splitString = childNode.InnerText.Split(',');
                    for (int i = 0; i < splitString.Length; i++)
                    {
                        int gt;
                        if (NumberFormats.TryParseIntVb6(splitString[i], out gt))
                        {
                            currentPatch.DummyGroundTypes.Add(gt);
                        }
                    }
                    break;

                case "Derailments":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "0" || t == "false")
                    {
                        currentPatch.Derailments = false;
                    }
                    else
                    {
                        currentPatch.Derailments = true;
                    }
                    break;

                case "Toppling":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "0" || t == "false")
                    {
                        currentPatch.Derailments = false;
                    }
                    else
                    {
                        currentPatch.Derailments = true;
                    }
                    break;

                case "SignalSet":
                    string signalFile = Path.CombineFile(Plugin.FileSystem.GetDataFolder("Compatibility\\Signals"), childNode.InnerText.Trim());
                    if (File.Exists(signalFile))
                    {
                        currentPatch.CompatibilitySignalSet = signalFile;
                    }
                    break;

                case "AccurateObjectDisposal":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.AccurateObjectDisposal = true;
                    }
                    else
                    {
                        currentPatch.AccurateObjectDisposal = false;
                    }
                    break;

                case "SplitLineHack":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.SplitLineHack = true;
                    }
                    else
                    {
                        currentPatch.SplitLineHack = false;
                    }
                    break;

                case "AllowTrackPositionArguments":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.AllowTrackPositionArguments = true;
                    }
                    else
                    {
                        currentPatch.AllowTrackPositionArguments = false;
                    }
                    break;

                case "DisableSemiTransparentFaces":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.DisableSemiTransparentFaces = true;
                    }
                    else
                    {
                        currentPatch.DisableSemiTransparentFaces = false;
                    }
                    break;

                case "ReducedColorTransparency":
                    t = childNode.InnerText.Trim().ToLowerInvariant();
                    if (t == "1" || t == "true")
                    {
                        currentPatch.ReducedColorTransparency = true;
                    }
                    else
                    {
                        currentPatch.ReducedColorTransparency = false;
                    }
                    break;
                }
            }

            if (!routeFixes.ContainsKey(currentHash))
            {
                routeFixes.Add(currentHash, currentPatch);
            }
            else
            {
                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The RoutePatches database contains a duplicate entry with hash " + currentHash);
            }
        }
Пример #18
0
        private static void ParseTouchCommandEntryNode(string fileName, XElement parent, ICollection <CommandEntry> entries)
        {
            foreach (XElement childNode in parent.Elements())
            {
                if (childNode.Name.LocalName.ToLowerInvariant() != "entry")
                {
                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"Invalid entry node {childNode.Name.LocalName} in XML node {parent.Name.LocalName} at line {((IXmlLineInfo)childNode).LineNumber}");
                }
                else
                {
                    CommandEntry entry = new CommandEntry();
                    System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.InvariantCulture;

                    string section = childNode.Name.LocalName;

                    foreach (XElement keyNode in childNode.Elements())
                    {
                        string key        = keyNode.Name.LocalName;
                        string value      = keyNode.Value;
                        int    lineNumber = ((IXmlLineInfo)keyNode).LineNumber;

                        switch (keyNode.Name.LocalName.ToLowerInvariant())
                        {
                        case "name":
                            if (string.Compare(value, "N/A", StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                break;
                            }

                            int i;

                            for (i = 0; i < Translations.CommandInfos.Length; i++)
                            {
                                if (string.Compare(value, Translations.CommandInfos[i].Name, StringComparison.OrdinalIgnoreCase) == 0)
                                {
                                    break;
                                }
                            }

                            if (i == Translations.CommandInfos.Length || Translations.CommandInfos[i].Type != Translations.CommandType.Digital)
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, $"value is invalid in {key} in {section} at line {lineNumber.ToString(culture)} in {fileName}");
                            }
                            else
                            {
                                entry.Command = Translations.CommandInfos[i].Command;
                            }
                            break;

                        case "option":
                            if (value.Any())
                            {
                                int option;

                                if (!NumberFormats.TryParseIntVb6(value, out option))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"value is invalid in {key} in {section} at line {lineNumber.ToString(culture)} in {fileName}");
                                }
                                else
                                {
                                    entry.Option = option;
                                }
                            }
                            break;
                        }
                    }

                    entries.Add(entry);
                }
            }
        }
Пример #19
0
        private static void ParsePanelAnimatedNode(XElement Element, string FileName, string TrainPath, TrainManager.Train Train, int Car, TrainManager.CarSection CarSection, int GroupIndex)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;

            int    currentSectionElement   = 0;
            int    numberOfSectionElements = Element.Elements().Count();
            double invfac = numberOfSectionElements == 0 ? Loading.TrainProgressCurrentWeight : Loading.TrainProgressCurrentWeight / (double)numberOfSectionElements;

            foreach (XElement SectionElement in Element.Elements())
            {
                Loading.TrainProgress = Loading.TrainProgressCurrentSum + invfac * (double)currentSectionElement;
                if ((currentSectionElement & 4) == 0)
                {
                    System.Threading.Thread.Sleep(1);
                    if (Loading.Cancel)
                    {
                        return;
                    }
                }

                string Section = SectionElement.Name.LocalName;

                switch (SectionElement.Name.LocalName.ToLowerInvariant())
                {
                case "group":
                    if (GroupIndex == 0)
                    {
                        int n = 0;

                        foreach (XElement KeyNode in SectionElement.Elements())
                        {
                            string Key        = KeyNode.Name.LocalName;
                            string Value      = KeyNode.Value;
                            int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                            switch (Key.ToLowerInvariant())
                            {
                            case "number":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out n))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;
                            }
                        }

                        if (n + 1 >= CarSection.Groups.Length)
                        {
                            Array.Resize(ref CarSection.Groups, n + 2);
                            CarSection.Groups[n + 1] = new TrainManager.ElementsGroup
                            {
                                Elements = new ObjectManager.AnimatedObject[] { },
                                Overlay  = true
                            };
                        }

                        ParsePanelAnimatedNode(SectionElement, FileName, TrainPath, Train, Car, CarSection, n + 1);
                    }
                    break;

                case "touch":
                    if (GroupIndex > 0)
                    {
                        Vector3 Position             = Vector3.Zero;
                        Vector3 Size                 = Vector3.Zero;
                        int     JumpScreen           = GroupIndex - 1;
                        int     SoundIndex           = -1;
                        Translations.Command Command = Translations.Command.None;
                        int CommandOption            = 0;

                        foreach (XElement KeyNode in SectionElement.Elements())
                        {
                            string Key        = KeyNode.Name.LocalName;
                            string Value      = KeyNode.Value;
                            int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                            switch (Key.ToLowerInvariant())
                            {
                            case "position":
                            {
                                string[] s = Value.Split(',');
                                if (s.Length == 3)
                                {
                                    if (s[0].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[0], out Position.X))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "X is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[1].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[1], out Position.Y))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Y is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[2].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[2], out Position.Z))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Z is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Three arguments are expected in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                            break;

                            case "size":
                            {
                                string[] s = Value.Split(',');
                                if (s.Length == 3)
                                {
                                    if (s[0].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[0], out Size.X))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "X is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[1].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[1], out Size.Y))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Y is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                    if (s[2].Length != 0 && !NumberFormats.TryParseDoubleVb6(s[2], out Size.Z))
                                    {
                                        Interface.AddMessage(MessageType.Error, false, "Z is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Three arguments are expected in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                            break;

                            case "jumpscreen":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out JumpScreen))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "soundindex":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out SoundIndex))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "command":
                            {
                                int i;
                                for (i = 0; i < Translations.CommandInfos.Length; i++)
                                {
                                    if (string.Compare(Value, Translations.CommandInfos[i].Name, StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        break;
                                    }
                                }
                                if (i == Translations.CommandInfos.Length || Translations.CommandInfos[i].Type != Translations.CommandType.Digital)
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                else
                                {
                                    Command = Translations.CommandInfos[i].Command;
                                }
                            }
                            break;

                            case "commandoption":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out CommandOption))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;
                            }
                        }
                        CreateTouchElement(CarSection.Groups[GroupIndex], Position, Size, JumpScreen, SoundIndex, Command, CommandOption);
                    }
                    break;

                case "include":
                {
                    foreach (XElement KeyNode in SectionElement.Elements())
                    {
                        string Key        = KeyNode.Name.LocalName;
                        string Value      = KeyNode.Value;
                        int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                        switch (Key.ToLowerInvariant())
                        {
                        case "filename":
                        {
                            string File = OpenBveApi.Path.CombineFile(TrainPath, Value);
                            if (System.IO.File.Exists(File))
                            {
                                System.Text.Encoding e = TextEncoding.GetSystemEncodingFromFile(File);
                                ObjectManager.AnimatedObjectCollection a = AnimatedObjectParser.ReadObject(File, e);
                                if (a != null)
                                {
                                    for (int i = 0; i < a.Objects.Length; i++)
                                    {
                                        a.Objects[i].ObjectIndex = ObjectManager.CreateDynamicObject();
                                    }
                                    CarSection.Groups[GroupIndex].Elements = a.Objects;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                        }
                        break;
                        }
                    }
                }
                break;
                }
            }
        }
Пример #20
0
        /// <summary>This function processes the list of expressions for $Char, $Rnd, $If and $Sub directives, and evaluates them into the final expressions dataset</summary>
        private void PreprocessChrRndSub(string FileName, System.Text.Encoding Encoding, ref Expression[] Expressions)
        {
            string[] Subs    = new string[16];
            int      openIfs = 0;

            for (int i = 0; i < Expressions.Length; i++)
            {
                string Epilog = " at line " + Expressions[i].Line.ToString(Culture) + ", column " + Expressions[i].Column.ToString(Culture) + " in file " + Expressions[i].File;
                bool   continueWithNextExpression = false;
                for (int j = Expressions[i].Text.Length - 1; j >= 0; j--)
                {
                    if (Expressions[i].Text[j] == '$')
                    {
                        int k;
                        for (k = j + 1; k < Expressions[i].Text.Length; k++)
                        {
                            if (Expressions[i].Text[k] == '(')
                            {
                                break;
                            }
                            else if (Expressions[i].Text[k] == '/' | Expressions[i].Text[k] == '\\')
                            {
                                k = Expressions[i].Text.Length + 1;
                                break;
                            }
                        }
                        if (k <= Expressions[i].Text.Length)
                        {
                            string t = Expressions[i].Text.Substring(j, k - j).TrimEnd(new char[] { });
                            int    l = 1, h;
                            for (h = k + 1; h < Expressions[i].Text.Length; h++)
                            {
                                switch (Expressions[i].Text[h])
                                {
                                case '(':
                                    l++;
                                    break;

                                case ')':
                                    l--;
                                    if (l < 0)
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid parenthesis structure in " + t + Epilog);
                                    }
                                    break;
                                }
                                if (l <= 0)
                                {
                                    break;
                                }
                            }
                            if (continueWithNextExpression)
                            {
                                break;
                            }
                            if (l != 0)
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Invalid parenthesis structure in " + t + Epilog);
                                break;
                            }
                            string s = Expressions[i].Text.Substring(k + 1, h - k - 1).Trim(new char[] { });
                            switch (t.ToLowerInvariant())
                            {
                            case "$if":
                                if (j != 0)
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The $If directive must not appear within another statement" + Epilog);
                                }
                                else
                                {
                                    double num;
                                    if (double.TryParse(s, NumberStyles.Float, Culture, out num))
                                    {
                                        openIfs++;
                                        Expressions[i].Text = string.Empty;
                                        if (num == 0.0)
                                        {
                                            /*
                                             * Blank every expression until the matching $Else or $EndIf
                                             * */
                                            i++;
                                            int level = 1;
                                            while (i < Expressions.Length)
                                            {
                                                if (Expressions[i].Text.StartsWith("$if", StringComparison.OrdinalIgnoreCase))
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                    level++;
                                                }
                                                else if (Expressions[i].Text.StartsWith("$else", StringComparison.OrdinalIgnoreCase))
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                    if (level == 1)
                                                    {
                                                        level--;
                                                        break;
                                                    }
                                                }
                                                else if (Expressions[i].Text.StartsWith("$endif", StringComparison.OrdinalIgnoreCase))
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                    level--;
                                                    if (level == 0)
                                                    {
                                                        openIfs--;
                                                        break;
                                                    }
                                                }
                                                else
                                                {
                                                    Expressions[i].Text = string.Empty;
                                                }
                                                i++;
                                            }
                                            if (level != 0)
                                            {
                                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$EndIf missing at the end of the file" + Epilog);
                                            }
                                        }
                                        continueWithNextExpression = true;
                                        break;
                                    }
                                    else
                                    {
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The $If condition does not evaluate to a number" + Epilog);
                                    }
                                }
                                continueWithNextExpression = true;
                                break;

                            case "$else":
                                /*
                                 * Blank every expression until the matching $EndIf
                                 * */
                                Expressions[i].Text = string.Empty;
                                if (openIfs != 0)
                                {
                                    i++;
                                    int level = 1;
                                    while (i < Expressions.Length)
                                    {
                                        if (Expressions[i].Text.StartsWith("$if", StringComparison.OrdinalIgnoreCase))
                                        {
                                            Expressions[i].Text = string.Empty;
                                            level++;
                                        }
                                        else if (Expressions[i].Text.StartsWith("$else", StringComparison.OrdinalIgnoreCase))
                                        {
                                            Expressions[i].Text = string.Empty;
                                            if (level == 1)
                                            {
                                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Duplicate $Else encountered" + Epilog);
                                            }
                                        }
                                        else if (Expressions[i].Text.StartsWith("$endif", StringComparison.OrdinalIgnoreCase))
                                        {
                                            Expressions[i].Text = string.Empty;
                                            level--;
                                            if (level == 0)
                                            {
                                                openIfs--;
                                                break;
                                            }
                                        }
                                        else
                                        {
                                            Expressions[i].Text = string.Empty;
                                        }
                                        i++;
                                    }
                                    if (level != 0)
                                    {
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$EndIf missing at the end of the file" + Epilog);
                                    }
                                }
                                else
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$Else without matching $If encountered" + Epilog);
                                }
                                continueWithNextExpression = true;
                                break;

                            case "$endif":
                                Expressions[i].Text = string.Empty;
                                if (openIfs != 0)
                                {
                                    openIfs--;
                                }
                                else
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "$EndIf without matching $If encountered" + Epilog);
                                }
                                continueWithNextExpression = true;
                                break;

                            case "$include":
                                if (j != 0)
                                {
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The $Include directive must not appear within another statement" + Epilog);
                                    continueWithNextExpression = true;
                                    break;
                                }
                                string[] args = s.Split(new char[] { ';' });
                                for (int ia = 0; ia < args.Length; ia++)
                                {
                                    args[ia] = args[ia].Trim(new char[] { });
                                }
                                int      count        = (args.Length + 1) / 2;
                                string[] files        = new string[count];
                                double[] weights      = new double[count];
                                double[] offsets      = new double[count];
                                double   weightsTotal = 0.0;
                                for (int ia = 0; ia < count; ia++)
                                {
                                    string file;
                                    double offset;
                                    int    colon = args[2 * ia].IndexOf(':');
                                    if (colon >= 0)
                                    {
                                        file = args[2 * ia].Substring(0, colon).TrimEnd(new char[] { });
                                        string value = args[2 * ia].Substring(colon + 1).TrimStart(new char[] { });
                                        if (!double.TryParse(value, NumberStyles.Float, Culture, out offset))
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The track position offset " + value + " is invalid in " + t + Epilog);
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        file   = args[2 * ia];
                                        offset = 0.0;
                                    }
                                    files[ia]   = Path.CombineFile(System.IO.Path.GetDirectoryName(FileName), file);
                                    offsets[ia] = offset;
                                    if (!System.IO.File.Exists(files[ia]))
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "The file " + file + " could not be found in " + t + Epilog);
                                        for (int ta = i; ta < Expressions.Length - 1; ta++)
                                        {
                                            Expressions[ta] = Expressions[ta + 1];
                                        }
                                        Array.Resize(ref Expressions, Expressions.Length - 1);
                                        i--;
                                        break;
                                    }
                                    if (2 * ia + 1 < args.Length)
                                    {
                                        if (!NumberFormats.TryParseDoubleVb6(args[2 * ia + 1], out weights[ia]))
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "A weight is invalid in " + t + Epilog);
                                            break;
                                        }
                                        if (weights[ia] <= 0.0)
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "A weight is not positive in " + t + Epilog);
                                            break;
                                        }
                                        weightsTotal += weights[ia];
                                    }
                                    else
                                    {
                                        weights[ia]   = 1.0;
                                        weightsTotal += 1.0;
                                    }
                                }
                                if (count == 0)
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "No file was specified in " + t + Epilog);
                                    break;
                                }
                                if (!continueWithNextExpression)
                                {
                                    double number      = Plugin.RandomNumberGenerator.NextDouble() * weightsTotal;
                                    double value       = 0.0;
                                    int    chosenIndex = 0;
                                    for (int ia = 0; ia < count; ia++)
                                    {
                                        value += weights[ia];
                                        if (value > number)
                                        {
                                            chosenIndex = ia;
                                            break;
                                        }
                                    }
                                    Expression[] expr;
                                    //Get the text encoding of our $Include file
                                    System.Text.Encoding includeEncoding = TextEncoding.GetSystemEncodingFromFile(files[chosenIndex]);
                                    if (!includeEncoding.Equals(Encoding) && includeEncoding.WindowsCodePage != Encoding.WindowsCodePage)
                                    {
                                        //If the encodings do not match, add a warning
                                        //This is not critical, but it's a bad idea to mix and match character encodings within a routefile, as the auto-detection may sometimes be wrong
                                        Plugin.CurrentHost.AddMessage(MessageType.Warning, false, "The text encoding of the $Include file " + files[chosenIndex] + " does not match that of the base routefile.");
                                    }
                                    string[] lines = System.IO.File.ReadAllLines(files[chosenIndex], includeEncoding);
                                    PreprocessSplitIntoExpressions(files[chosenIndex], lines, out expr, false, offsets[chosenIndex] + Expressions[i].TrackPositionOffset);
                                    int length = Expressions.Length;
                                    if (expr.Length == 0)
                                    {
                                        for (int ia = i; ia < Expressions.Length - 1; ia++)
                                        {
                                            Expressions[ia] = Expressions[ia + 1];
                                        }
                                        Array.Resize(ref Expressions, length - 1);
                                    }
                                    else
                                    {
                                        Array.Resize(ref Expressions, length + expr.Length - 1);
                                        for (int ia = Expressions.Length - 1; ia >= i + expr.Length; ia--)
                                        {
                                            Expressions[ia] = Expressions[ia - expr.Length + 1];
                                        }
                                        for (int ia = 0; ia < expr.Length; ia++)
                                        {
                                            Expressions[i + ia] = expr[ia];
                                        }
                                    }
                                    i--;
                                    continueWithNextExpression = true;
                                }
                                break;

                            case "$chr":
                            case "$chruni":
                            {
                                int x;
                                if (NumberFormats.TryParseIntVb6(s, out x))
                                {
                                    if (x < 0)
                                    {
                                        //Must be non-negative
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index must be a non-negative character in " + t + Epilog);
                                    }
                                    else
                                    {
                                        Expressions[i].Text = Expressions[i].Text.Substring(0, j) + char.ConvertFromUtf32(x) + Expressions[i].Text.Substring(h + 1);
                                    }
                                }
                                else
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                }
                            } break;

                            case "$chrascii":
                            {
                                int x;
                                if (NumberFormats.TryParseIntVb6(s, out x))
                                {
                                    if (x < 0 || x > 127)
                                    {
                                        //Standard ASCII characters from 0-127
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index does not correspond to a valid ASCII character in " + t + Epilog);
                                    }
                                    else
                                    {
                                        Expressions[i].Text = Expressions[i].Text.Substring(0, j) + char.ConvertFromUtf32(x) + Expressions[i].Text.Substring(h + 1);
                                    }
                                }
                                else
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                }
                            }
                            break;

                            case "$rnd":
                            {
                                int m = s.IndexOf(";", StringComparison.Ordinal);
                                if (m >= 0)
                                {
                                    string s1 = s.Substring(0, m).TrimEnd(new char[] { });
                                    string s2 = s.Substring(m + 1).TrimStart(new char[] { });
                                    int    x; if (NumberFormats.TryParseIntVb6(s1, out x))
                                    {
                                        int y; if (NumberFormats.TryParseIntVb6(s2, out y))
                                        {
                                            int z = x + (int)Math.Floor(Plugin.RandomNumberGenerator.NextDouble() * (y - x + 1));
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + z.ToString(Culture) + Expressions[i].Text.Substring(h + 1);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index2 is invalid in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index1 is invalid in " + t + Epilog);
                                    }
                                }
                                else
                                {
                                    continueWithNextExpression = true;
                                    Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Two arguments are expected in " + t + Epilog);
                                }
                            } break;

                            case "$sub":
                            {
                                l = 0;
                                bool f = false;
                                int  m;
                                for (m = h + 1; m < Expressions[i].Text.Length; m++)
                                {
                                    switch (Expressions[i].Text[m])
                                    {
                                    case '(': l++; break;

                                    case ')': l--; break;

                                    case '=':
                                        if (l == 0)
                                        {
                                            f = true;
                                        }
                                        break;

                                    default:
                                        if (!char.IsWhiteSpace(Expressions[i].Text[m]))
                                        {
                                            l = -1;
                                        }
                                        break;
                                    }
                                    if (f | l < 0)
                                    {
                                        break;
                                    }
                                }
                                if (f)
                                {
                                    l = 0;
                                    int n;
                                    for (n = m + 1; n < Expressions[i].Text.Length; n++)
                                    {
                                        switch (Expressions[i].Text[n])
                                        {
                                        case '(': l++; break;

                                        case ')': l--; break;
                                        }
                                        if (l < 0)
                                        {
                                            break;
                                        }
                                    }
                                    int x;
                                    if (NumberFormats.TryParseIntVb6(s, out x))
                                    {
                                        if (x >= 0)
                                        {
                                            while (x >= Subs.Length)
                                            {
                                                Array.Resize(ref Subs, Subs.Length << 1);
                                            }
                                            Subs[x]             = Expressions[i].Text.Substring(m + 1, n - m - 1).Trim(new char[] { });
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + Expressions[i].Text.Substring(n);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is expected to be non-negative in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                    }
                                }
                                else
                                {
                                    int x;
                                    if (NumberFormats.TryParseIntVb6(s, out x))
                                    {
                                        if (x >= 0 & x < Subs.Length && Subs[x] != null)
                                        {
                                            Expressions[i].Text = Expressions[i].Text.Substring(0, j) + Subs[x] + Expressions[i].Text.Substring(h + 1);
                                        }
                                        else
                                        {
                                            continueWithNextExpression = true;
                                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is out of range in " + t + Epilog);
                                        }
                                    }
                                    else
                                    {
                                        continueWithNextExpression = true;
                                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Index is invalid in " + t + Epilog);
                                    }
                                }
                            }
                            break;
                            }
                        }
                    }
                    if (continueWithNextExpression)
                    {
                        break;
                    }
                }
            }
            // handle comments introduced via chr, rnd, sub
            {
                int length = Expressions.Length;
                for (int i = 0; i < length; i++)
                {
                    Expressions[i].Text = Expressions[i].Text.Trim(new char[] { });
                    if (Expressions[i].Text.Length != 0)
                    {
                        if (Expressions[i].Text[0] == ';')
                        {
                            for (int j = i; j < length - 1; j++)
                            {
                                Expressions[j] = Expressions[j + 1];
                            }
                            length--;
                            i--;
                        }
                    }
                    else
                    {
                        for (int j = i; j < length - 1; j++)
                        {
                            Expressions[j] = Expressions[j + 1];
                        }
                        length--;
                        i--;
                    }
                }
                if (length != Expressions.Length)
                {
                    Array.Resize(ref Expressions, length);
                }
            }
        }
Пример #21
0
        /// <summary>Parses a base track following object node</summary>
        /// <param name="Element">The XElement to parse</param>
        /// <param name="FileName">The filename of the containing XML file</param>
        /// <param name="Path">The path of the containing XML file</param>
        /// <param name="Train">The track following object to parse this node into</param>
        private static void ParseTrackFollowingObjectNode(XElement Element, string FileName, string Path, string ObjectPath, TrainManager.TrackFollowingObject Train)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            string TrainDirectory       = string.Empty;
            bool   consistReversed      = false;
            List <Game.TravelData> Data = new List <Game.TravelData>();

            foreach (XElement SectionElement in Element.Elements())
            {
                string Section = SectionElement.Name.LocalName;

                switch (SectionElement.Name.LocalName.ToLowerInvariant())
                {
                case "stops":
                    ParseStopNode(SectionElement, FileName, Data);
                    break;

                case "train":
                    foreach (XElement KeyNode in SectionElement.Elements())
                    {
                        string Key        = KeyNode.Name.LocalName;
                        string Value      = KeyNode.Value;
                        int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                        switch (Key.ToLowerInvariant())
                        {
                        case "directory":
                        {
                            string trainDirectory = OpenBveApi.Path.CombineDirectory(Path, Value);
                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                trainDirectory = OpenBveApi.Path.CombineFile(Program.FileSystem.InitialTrainFolder, Value);
                            }
                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                trainDirectory = OpenBveApi.Path.CombineFile(Program.FileSystem.TrainInstallationDirectory, Value);
                            }
                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                trainDirectory = OpenBveApi.Path.CombineFile(ObjectPath, Value);
                            }

                            if (!System.IO.Directory.Exists(trainDirectory))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Directory was not found in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            else
                            {
                                TrainDirectory = trainDirectory;
                            }
                        }
                        break;

                        case "reversed":
                            int n;
                            NumberFormats.TryParseIntVb6(Value, out n);
                            if (n == 1 || Value.ToLowerInvariant() == "true")
                            {
                                consistReversed = true;
                            }
                            break;
                        }
                    }
                    break;

                case "definition":
                    foreach (XElement KeyNode in SectionElement.Elements())
                    {
                        string Key        = KeyNode.Name.LocalName;
                        string Value      = KeyNode.Value;
                        int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                        switch (Key.ToLowerInvariant())
                        {
                        case "appearancetime":
                            if (Value.Length != 0 && !Interface.TryParseTime(Value, out Train.AppearanceTime))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "appearancestartposition":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceStartPosition))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "appearanceendposition":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Train.AppearanceEndPosition))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "leavetime":
                            if (Value.Length != 0 && !Interface.TryParseTime(Value, out Train.LeaveTime))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;
                        }
                    }
                    break;
                }
            }

            if (!Data.Any() || string.IsNullOrEmpty(TrainDirectory))
            {
                return;
            }

            /*
             * First check for a train.ai file- Functionally identical, but allows for differently configured AI
             * trains not to show up as driveable
             */
            string TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.ai");

            if (!System.IO.File.Exists(TrainData))
            {
                // Check for the standard driveable train.dat
                TrainData = OpenBveApi.Path.CombineFile(TrainDirectory, "train.dat");
            }
            string ExteriorFile = OpenBveApi.Path.CombineFile(TrainDirectory, "extensions.cfg");

            if (!System.IO.File.Exists(TrainData) || !System.IO.File.Exists(ExteriorFile))
            {
                Interface.AddMessage(MessageType.Error, true, "The supplied train folder in TrackFollowingObject " + FileName + " did not contain a complete set of data.");
                return;
            }
            TrainDatParser.ParseTrainData(TrainData, TextEncoding.GetSystemEncodingFromFile(TrainData), Train);
            SoundCfgParser.ParseSoundConfig(TrainDirectory, Train);
            Train.AI = new Game.TrackFollowingObjectAI(Train, Data);

            UnifiedObject[] CarObjects     = new UnifiedObject[Train.Cars.Length];
            UnifiedObject[] BogieObjects   = new UnifiedObject[Train.Cars.Length * 2];
            UnifiedObject[] CouplerObjects = new UnifiedObject[Train.Cars.Length - 1];
            ExtensionsCfgParser.ParseExtensionsConfig(System.IO.Path.GetDirectoryName(ExteriorFile), TextEncoding.GetSystemEncodingFromFile(ExteriorFile), ref CarObjects, ref BogieObjects, ref CouplerObjects, Train, true);

            int currentBogieObject = 0;

            for (int i = 0; i < Train.Cars.Length; i++)
            {
                if (CarObjects[i] == null)
                {
                    // load default exterior object
                    string       file = OpenBveApi.Path.CombineFile(Program.FileSystem.GetDataFolder("Compatibility"), "exterior.csv");
                    StaticObject so   = ObjectManager.LoadStaticObject(file, System.Text.Encoding.UTF8, false);
                    if (so == null)
                    {
                        CarObjects[i] = null;
                    }
                    else
                    {
                        double sx = Train.Cars[i].Width;
                        double sy = Train.Cars[i].Height;
                        double sz = Train.Cars[i].Length;
                        so.ApplyScale(sx, sy, sz);
                        CarObjects[i] = so;
                    }
                }
                if (CarObjects[i] != null)
                {
                    // add object
                    Train.Cars[i].LoadCarSections(CarObjects[i]);
                }

                //Load bogie objects
                if (BogieObjects[currentBogieObject] != null)
                {
                    Train.Cars[i].FrontBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                }
                currentBogieObject++;
                if (BogieObjects[currentBogieObject] != null)
                {
                    Train.Cars[i].RearBogie.LoadCarSections(BogieObjects[currentBogieObject]);
                }
                currentBogieObject++;
            }

            // door open/close speed
            foreach (var Car in Train.Cars)
            {
                if (Car.Specs.DoorOpenFrequency <= 0.0)
                {
                    if (Car.Doors[0].OpenSound.Buffer != null & Car.Doors[1].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        Program.Sounds.LoadBuffer(Car.Doors[1].OpenSound.Buffer);
                        double a = Car.Doors[0].OpenSound.Buffer.Duration;
                        double b = Car.Doors[1].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                    }
                    else if (Car.Doors[0].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        double a = Car.Doors[0].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = a > 0.0 ? 1.0 / a : 0.8;
                    }
                    else if (Car.Doors[1].OpenSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].OpenSound.Buffer);
                        double b = Car.Doors[1].OpenSound.Buffer.Duration;
                        Car.Specs.DoorOpenFrequency = b > 0.0 ? 1.0 / b : 0.8;
                    }
                    else
                    {
                        Car.Specs.DoorOpenFrequency = 0.8;
                    }
                }
                if (Car.Specs.DoorCloseFrequency <= 0.0)
                {
                    if (Car.Doors[0].CloseSound.Buffer != null & Car.Doors[1].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        Program.Sounds.LoadBuffer(Car.Doors[1].CloseSound.Buffer);
                        double a = Car.Doors[0].CloseSound.Buffer.Duration;
                        double b = Car.Doors[1].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = a + b > 0.0 ? 2.0 / (a + b) : 0.8;
                    }
                    else if (Car.Doors[0].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        double a = Car.Doors[0].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = a > 0.0 ? 1.0 / a : 0.8;
                    }
                    else if (Car.Doors[1].CloseSound.Buffer != null)
                    {
                        Program.Sounds.LoadBuffer(Car.Doors[0].CloseSound.Buffer);
                        double b = Car.Doors[1].CloseSound.Buffer.Duration;
                        Car.Specs.DoorCloseFrequency = b > 0.0 ? 1.0 / b : 0.8;
                    }
                    else
                    {
                        Car.Specs.DoorCloseFrequency = 0.8;
                    }
                }
                const double f = 0.015;
                const double g = 2.75;
                Car.Specs.DoorOpenPitch       = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                Car.Specs.DoorClosePitch      = Math.Exp(f * Math.Tan(g * (Program.RandomNumberGenerator.NextDouble() - 0.5)));
                Car.Specs.DoorOpenFrequency  /= Car.Specs.DoorOpenPitch;
                Car.Specs.DoorCloseFrequency /= Car.Specs.DoorClosePitch;

                /*
                 * Remove the following two lines, then the pitch at which doors play
                 * takes their randomized opening and closing times into account.
                 * */
                Car.Specs.DoorOpenPitch  = 1.0;
                Car.Specs.DoorClosePitch = 1.0;
            }

            foreach (var Car in Train.Cars)
            {
                Car.FrontAxle.Follower.TrackIndex            = Data[0].RailIndex;
                Car.RearAxle.Follower.TrackIndex             = Data[0].RailIndex;
                Car.FrontBogie.FrontAxle.Follower.TrackIndex = Data[0].RailIndex;
                Car.FrontBogie.RearAxle.Follower.TrackIndex  = Data[0].RailIndex;
                Car.RearBogie.FrontAxle.Follower.TrackIndex  = Data[0].RailIndex;
                Car.RearBogie.RearAxle.Follower.TrackIndex   = Data[0].RailIndex;
            }

            if (consistReversed)
            {
                Train.Reverse();
            }
            Train.PlaceCars(Data[0].StopPosition);
        }
Пример #22
0
        /// <summary>Parses a train travel stop node</summary>
        /// <param name="Element">The XElement to parse</param>
        /// <param name="FileName">The filename of the containing XML file</param>
        /// <param name="Data">The list of travel data to add this to</param>
        private static void ParseStopNode(XElement Element, string FileName, List <Game.TravelData> Data)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;

            foreach (XElement SectionElement in Element.Elements())
            {
                string Section = SectionElement.Name.LocalName;

                switch (SectionElement.Name.LocalName.ToLowerInvariant())
                {
                case "stop":
                {
                    Game.TravelData NewData     = new Game.TravelData();
                    double          Decelerate  = 0.0;
                    double          Accelerate  = 0.0;
                    double          TargetSpeed = 0.0;

                    foreach (XElement KeyNode in SectionElement.Elements())
                    {
                        string Key        = KeyNode.Name.LocalName;
                        string Value      = KeyNode.Value;
                        int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                        switch (Key.ToLowerInvariant())
                        {
                        case "decelerate":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Decelerate))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "stopposition":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out NewData.StopPosition))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "stoptime":
                            if (Value.Length != 0 && !Interface.TryParseTime(Value, out NewData.StopTime))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "doors":
                        {
                            int  door     = 0;
                            bool doorboth = false;

                            switch (Value.ToLowerInvariant())
                            {
                            case "l":
                            case "left":
                                door = -1;
                                break;

                            case "r":
                            case "right":
                                door = 1;
                                break;

                            case "n":
                            case "none":
                            case "neither":
                                door = 0;
                                break;

                            case "b":
                            case "both":
                                doorboth = true;
                                break;

                            default:
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out door))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    door = 0;
                                }
                                break;
                            }

                            NewData.OpenLeftDoors  = door < 0.0 | doorboth;
                            NewData.OpenRightDoors = door > 0.0 | doorboth;
                        }
                        break;

                        case "accelerate":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out Accelerate))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "targetspeed":
                            if (Value.Length != 0 && !NumberFormats.TryParseDoubleVb6(Value, out TargetSpeed))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;

                        case "direction":
                        {
                            int d = 0;
                            switch (Value.ToLowerInvariant())
                            {
                            case "f":
                                d = 1;
                                break;

                            case "r":
                                d = -1;
                                break;

                            default:
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out d))
                                {
                                    Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;
                            }
                            if (d == 1 || d == -1)
                            {
                                NewData.Direction = (Game.TravelDirection)d;
                            }
                        }
                        break;

                        case "rail":
                            if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out NewData.RailIndex))
                            {
                                Interface.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                            }
                            break;
                        }
                    }

                    NewData.Decelerate  = Decelerate / 3.6;
                    NewData.Accelerate  = Accelerate / 3.6;
                    NewData.TargetSpeed = TargetSpeed / 3.6;
                    Data.Add(NewData);
                }
                break;
                }
            }
        }
Пример #23
0
        private static void ParseCarNode(XmlNode Node, string fileName, int Car, ref TrainManager.Train Train, ref UnifiedObject[] CarObjects, ref UnifiedObject[] BogieObjects)
        {
            string interiorFile = string.Empty;

            TrainManager.ReadhesionDeviceType readhesionDevice = Train.Specs.ReadhesionDeviceType;
            foreach (XmlNode c in Node.ChildNodes)
            {
                //Note: Don't use the short-circuiting operator, as otherwise we need another if
                switch (c.Name.ToLowerInvariant())
                {
                case "camerarestriction":
                    Train.Cars[Car].CameraRestrictionMode = CameraRestrictionMode.Restricted3D;
                    foreach (XmlNode cc in c.ChildNodes)
                    {
                        switch (cc.Name.ToLowerInvariant())
                        {
                        case "backwards":
                            if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].CameraRestriction.BottomLeft.Z))
                            {
                                Interface.AddMessage(MessageType.Warning, false, "Invalid backwards camera restriction defined for Car " + Car + " in XML file " + fileName);
                            }
                            break;

                        case "forwards":
                            if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].CameraRestriction.TopRight.Z))
                            {
                                Interface.AddMessage(MessageType.Warning, false, "Invalid forwards camera restriction defined for Car " + Car + " in XML file " + fileName);
                            }
                            break;

                        case "left":
                            if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].CameraRestriction.BottomLeft.X))
                            {
                                Interface.AddMessage(MessageType.Warning, false, "Invalid left camera restriction defined for Car " + Car + " in XML file " + fileName);
                            }
                            break;

                        case "right":
                            if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].CameraRestriction.TopRight.X))
                            {
                                Interface.AddMessage(MessageType.Warning, false, "Invalid right camera restriction defined for Car " + Car + " in XML file " + fileName);
                            }
                            break;

                        case "down":
                            if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].CameraRestriction.BottomLeft.Y))
                            {
                                Interface.AddMessage(MessageType.Warning, false, "Invalid down camera restriction defined for Car " + Car + " in XML file " + fileName);
                            }
                            break;

                        case "up":
                            if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].CameraRestriction.TopRight.Y))
                            {
                                Interface.AddMessage(MessageType.Warning, false, "Invalid up camera restriction defined for Car " + Car + " in XML file " + fileName);
                            }
                            break;
                        }
                    }
                    break;

                case "brake":
                    Train.Cars[Car].CarBrake.brakeType = BrakeType.Auxiliary;
                    if (c.ChildNodes.OfType <XmlElement>().Any())
                    {
                        ParseBrakeNode(c, fileName, Car, ref Train);
                    }
                    else if (!String.IsNullOrEmpty(c.InnerText))
                    {
                        try
                        {
                            string      childFile = OpenBveApi.Path.CombineFile(currentPath, c.InnerText);
                            XmlDocument childXML  = new XmlDocument();
                            childXML.Load(childFile);
                            XmlNodeList childNodes = childXML.DocumentElement.SelectNodes("/openBVE/Brake");
                            //We need to save and restore the current path to make relative paths within the child file work correctly
                            string savedPath = currentPath;
                            currentPath = System.IO.Path.GetDirectoryName(childFile);
                            ParseBrakeNode(childNodes[0], fileName, Car, ref Train);
                            currentPath = savedPath;
                        }
                        catch
                        {
                            Interface.AddMessage(MessageType.Error, false, "Failed to load the child Brake XML file specified in " + c.InnerText);
                        }
                    }
                    break;

                case "length":
                    double l;
                    if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out l) | l <= 0.0)
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Invalid length defined for Car " + Car + " in XML file " + fileName);
                        break;
                    }
                    Train.Cars[Car].Length = l;
                    break;

                case "width":
                    double w;
                    if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out w) | w <= 0.0)
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Invalid width defined for Car " + Car + " in XML file " + fileName);
                        break;
                    }
                    Train.Cars[Car].Width = w;
                    break;

                case "height":
                    double h;
                    if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out h) | h <= 0.0)
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Invalid height defined for Car " + Car + " in XML file " + fileName);
                        break;
                    }
                    Train.Cars[Car].Height = h;
                    break;

                case "motorcar":
                    if (c.InnerText.ToLowerInvariant() == "1" || c.InnerText.ToLowerInvariant() == "true")
                    {
                        Train.Cars[Car].Specs.IsMotorCar         = true;
                        Train.Cars[Car].Specs.AccelerationCurves = new TrainManager.AccelerationCurve[AccelerationCurves.Length];
                        for (int i = 0; i < AccelerationCurves.Length; i++)
                        {
                            Train.Cars[Car].Specs.AccelerationCurves[i] = AccelerationCurves[i].Clone(AccelerationCurves[i].Multiplier);
                        }
                    }
                    else
                    {
                        Train.Cars[Car].Specs.AccelerationCurves = new TrainManager.AccelerationCurve[] { };
                        Train.Cars[Car].Specs.IsMotorCar         = false;
                        Train.Cars[Car].Specs.ReAdhesionDevice   = new TrainManager.CarReAdhesionDevice(Train.Cars[Car]);
                    }
                    break;

                case "mass":
                    double m;
                    if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out m) | m <= 0.0)
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Invalid mass defined for Car " + Car + " in XML file " + fileName);
                        break;
                    }
                    Train.Cars[Car].Specs.MassEmpty   = m;
                    Train.Cars[Car].Specs.MassCurrent = m;
                    break;

                case "frontaxle":
                    if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out Train.Cars[Car].FrontAxle.Position))
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Invalid front axle position defined for Car " + Car + " in XML file " + fileName);
                    }
                    break;

                case "rearaxle":
                    if (!NumberFormats.TryParseDoubleVb6(c.InnerText, out Train.Cars[Car].RearAxle.Position))
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Invalid rear axle position defined for Car " + Car + " in XML file " + fileName);
                    }
                    break;

                case "object":
                    if (string.IsNullOrEmpty(c.InnerText))
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Invalid object path for Car " + Car + " in XML file " + fileName);
                        break;
                    }
                    string f = OpenBveApi.Path.CombineFile(currentPath, c.InnerText);
                    if (System.IO.File.Exists(f))
                    {
                        CarObjects[Car] = ObjectManager.LoadObject(f, System.Text.Encoding.Default, false);
                    }
                    break;

                case "reversed":
                    int n;
                    NumberFormats.TryParseIntVb6(c.InnerText, out n);
                    if (n == 1 || c.InnerText.ToLowerInvariant() == "true")
                    {
                        CarObjectsReversed[Car] = true;
                    }
                    break;

                case "loadingsway":
                    int nm;
                    NumberFormats.TryParseIntVb6(c.InnerText, out nm);
                    if (nm == 1 || c.InnerText.ToLowerInvariant() == "true")
                    {
                        Train.Cars[Car].EnableLoadingSway = true;
                    }
                    else
                    {
                        Train.Cars[Car].EnableLoadingSway = false;
                    }
                    break;

                case "frontbogie":
                    if (c.ChildNodes.OfType <XmlElement>().Any())
                    {
                        foreach (XmlNode cc in c.ChildNodes)
                        {
                            switch (cc.Name.ToLowerInvariant())
                            {
                            case "frontaxle":
                                if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].FrontBogie.FrontAxle.Position))
                                {
                                    Interface.AddMessage(MessageType.Warning, false, "Invalid front bogie, front axle position defined for Car " + Car + " in XML file " + fileName);
                                }
                                break;

                            case "rearaxle":
                                if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].FrontBogie.RearAxle.Position))
                                {
                                    Interface.AddMessage(MessageType.Warning, false, "Invalid front bogie, rear axle position defined for Car " + Car + " in XML file " + fileName);
                                }
                                break;

                            case "object":
                                if (string.IsNullOrEmpty(cc.InnerText))
                                {
                                    Interface.AddMessage(MessageType.Warning, false, "Invalid front bogie object path for Car " + Car + " in XML file " + fileName);
                                    break;
                                }
                                string fb = OpenBveApi.Path.CombineFile(currentPath, cc.InnerText);
                                if (System.IO.File.Exists(fb))
                                {
                                    BogieObjects[Car * 2] = ObjectManager.LoadObject(fb, System.Text.Encoding.Default, false);
                                }
                                break;

                            case "reversed":
                                int nn;
                                NumberFormats.TryParseIntVb6(cc.InnerText, out nn);
                                if (cc.InnerText.ToLowerInvariant() == "true" || nn == 1)
                                {
                                    BogieObjectsReversed[Car * 2] = true;
                                }
                                break;
                            }
                        }
                    }
                    break;

                case "rearbogie":
                    if (c.ChildNodes.OfType <XmlElement>().Any())
                    {
                        foreach (XmlNode cc in c.ChildNodes)
                        {
                            switch (cc.Name.ToLowerInvariant())
                            {
                            case "frontaxle":
                                if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].RearBogie.FrontAxle.Position))
                                {
                                    Interface.AddMessage(MessageType.Warning, false, "Invalid rear bogie, front axle position defined for Car " + Car + " in XML file " + fileName);
                                }
                                break;

                            case "rearaxle":
                                if (!NumberFormats.TryParseDoubleVb6(cc.InnerText, out Train.Cars[Car].RearBogie.RearAxle.Position))
                                {
                                    Interface.AddMessage(MessageType.Warning, false, "Invalid rear bogie, rear axle position defined for Car " + Car + " in XML file " + fileName);
                                }
                                break;

                            case "object":
                                if (string.IsNullOrEmpty(cc.InnerText))
                                {
                                    Interface.AddMessage(MessageType.Warning, false, "Invalid rear bogie object path for Car " + Car + " in XML file " + fileName);
                                    break;
                                }
                                string fb = OpenBveApi.Path.CombineFile(currentPath, cc.InnerText);
                                if (System.IO.File.Exists(fb))
                                {
                                    BogieObjects[Car * 2 + 1] = ObjectManager.LoadObject(fb, System.Text.Encoding.Default, false);
                                }
                                break;

                            case "reversed":
                                int nn;
                                NumberFormats.TryParseIntVb6(cc.InnerText, out nn);
                                if (cc.InnerText.ToLowerInvariant() == "true" || nn == 1)
                                {
                                    BogieObjectsReversed[Car * 2 + 1] = true;
                                }
                                break;
                            }
                        }
                    }
                    break;

                case "driverposition":
                    string[] splitText = c.InnerText.Split(new char[] { ',' });
                    if (splitText.Length != 3)
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Driver position must have three arguments for Car " + Car + " in XML file " + fileName);
                        break;
                    }
                    Train.Cars[Car].Driver = new Vector3();
                    double driverZ;
                    if (!NumberFormats.TryParseDoubleVb6(splitText[0], out Train.Cars[Car].Driver.X))
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Driver position X was invalid for Car " + Car + " in XML file " + fileName);
                    }
                    if (!NumberFormats.TryParseDoubleVb6(splitText[1], out Train.Cars[Car].Driver.Y))
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Driver position Y was invalid for Car " + Car + " in XML file " + fileName);
                    }
                    if (!NumberFormats.TryParseDoubleVb6(splitText[2], out driverZ))
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Driver position X was invalid for Car " + Car + " in XML file " + fileName);
                    }
                    Train.Cars[Car].Driver.Z = 0.5 * Train.Cars[Car].Length + driverZ;
                    break;

                case "interiorview":
                    if (!Train.IsPlayerTrain)
                    {
                        break;
                    }
                    Train.Cars[Car].HasInteriorView = true;
                    Train.Cars[Car].CarSections     = new TrainManager.CarSection[1];
                    Train.Cars[Car].CarSections[0]  = new TrainManager.CarSection
                    {
                        Groups = new TrainManager.ElementsGroup[1]
                    };
                    Train.Cars[Car].CarSections[0].Groups[0] = new TrainManager.ElementsGroup
                    {
                        Elements = new AnimatedObject[] { },
                        Overlay  = true
                    };

                    string cv = OpenBveApi.Path.CombineFile(currentPath, c.InnerText);
                    if (!System.IO.File.Exists(cv))
                    {
                        Interface.AddMessage(MessageType.Warning, false, "Interior view file was invalid for Car " + Car + " in XML file " + fileName);
                        break;
                    }
                    interiorFile = cv;
                    break;

                case "readhesiondevice":
                    switch (c.InnerText.ToLowerInvariant())
                    {
                    case "typea":
                    case "a":
                        readhesionDevice = TrainManager.ReadhesionDeviceType.TypeA;
                        break;

                    case "typeb":
                    case "b":
                        readhesionDevice = TrainManager.ReadhesionDeviceType.TypeB;
                        break;

                    case "typec":
                    case "c":
                        readhesionDevice = TrainManager.ReadhesionDeviceType.TypeC;
                        break;

                    case "typed":
                    case "d":
                        readhesionDevice = TrainManager.ReadhesionDeviceType.TypeD;
                        break;

                    default:
                        readhesionDevice = TrainManager.ReadhesionDeviceType.NotFitted;
                        break;
                    }
                    break;
                }
            }

            /*
             * As there is no set order for XML tags to be presented in, these must be
             * done after the end of the loop			 *
             */

            //Assign interior view
            if (interiorFile != String.Empty)
            {
                if (interiorFile.ToLowerInvariant().EndsWith(".xml"))
                {
                    XDocument CurrentXML = XDocument.Load(interiorFile, LoadOptions.SetLineInfo);

                    // Check for null
                    if (CurrentXML.Root == null)
                    {
                        // We couldn't find any valid XML, so return false
                        throw new System.IO.InvalidDataException();
                    }
                    IEnumerable <XElement> DocumentElements = CurrentXML.Root.Elements("PanelAnimated");
                    if (DocumentElements != null && DocumentElements.Count() != 0)
                    {
                        PanelAnimatedXmlParser.ParsePanelAnimatedXml(interiorFile, currentPath, Train, Car);
                        if (Train.Cars[Car].CameraRestrictionMode != CameraRestrictionMode.Restricted3D)
                        {
                            Train.Cars[Car].CameraRestrictionMode = CameraRestrictionMode.NotAvailable;
                        }
                        return;
                    }
                    DocumentElements = CurrentXML.Root.Elements("Panel");
                    if (DocumentElements != null && DocumentElements.Count() != 0)
                    {
                        PanelXmlParser.ParsePanelXml(interiorFile, currentPath, Train, Car);
                        Train.Cars[Car].CameraRestrictionMode = CameraRestrictionMode.On;
                        return;
                    }
                }
                else if (interiorFile.ToLowerInvariant().EndsWith(".cfg"))
                {
                    //Only supports panel2.cfg format
                    Panel2CfgParser.ParsePanel2Config(System.IO.Path.GetFileName(interiorFile), System.IO.Path.GetDirectoryName(interiorFile), Encoding.UTF8, Train, Car);
                    Train.Cars[Car].CameraRestrictionMode = CameraRestrictionMode.On;
                }
                else if (interiorFile.ToLowerInvariant().EndsWith(".animated"))
                {
                    UnifiedObject currentObject;
                    Program.CurrentHost.LoadObject(interiorFile, Encoding.UTF8, out currentObject);
                    var a = currentObject as AnimatedObjectCollection;
                    if (a != null)
                    {
                        try
                        {
                            for (int i = 0; i < a.Objects.Length; i++)
                            {
                                Program.CurrentHost.CreateDynamicObject(ref a.Objects[i].internalObject);
                            }
                            Train.Cars[Car].CarSections[0].Groups[0].Elements = a.Objects;
                            if (Train.Cars[Car].CameraRestrictionMode != CameraRestrictionMode.Restricted3D)
                            {
                                Train.Cars[Car].CameraRestrictionMode = CameraRestrictionMode.NotAvailable;
                            }
                        }
                        catch
                        {
                            Program.RestartArguments = " ";
                            Loading.Cancel           = true;
                        }
                    }
                }
                else
                {
                    Interface.AddMessage(MessageType.Warning, false, "Interior view file is not supported for Car " + Car + " in XML file " + fileName);
                }
            }
            //Assign readhesion device properties
            if (Train.Cars[Car].Specs.IsMotorCar)
            {
                switch (readhesionDevice)
                {
                case TrainManager.ReadhesionDeviceType.TypeA:
                    Train.Cars[Car].Specs.ReAdhesionDevice.UpdateInterval    = 1.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ApplicationFactor = 0.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseInterval   = 1.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseFactor     = 8.0;
                    break;

                case TrainManager.ReadhesionDeviceType.TypeB:
                    Train.Cars[Car].Specs.ReAdhesionDevice.UpdateInterval    = 0.1;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ApplicationFactor = 0.9935;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseInterval   = 4.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseFactor     = 1.125;
                    break;

                case TrainManager.ReadhesionDeviceType.TypeC:

                    Train.Cars[Car].Specs.ReAdhesionDevice.UpdateInterval    = 0.1;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ApplicationFactor = 0.965;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseInterval   = 2.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseFactor     = 1.5;
                    break;

                case TrainManager.ReadhesionDeviceType.TypeD:
                    Train.Cars[Car].Specs.ReAdhesionDevice.UpdateInterval    = 0.05;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ApplicationFactor = 0.935;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseInterval   = 0.3;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseFactor     = 2.0;
                    break;

                default:                         // no readhesion device
                    Train.Cars[Car].Specs.ReAdhesionDevice.UpdateInterval    = 1.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ApplicationFactor = 1.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseInterval   = 1.0;
                    Train.Cars[Car].Specs.ReAdhesionDevice.ReleaseFactor     = 99.0;
                    break;
                }
            }
        }
Пример #24
0
        private void ParsePanelAnimatedNode(XElement Element, string FileName, string TrainPath, TrainBase Train, int Car, CarSection CarSection, int GroupIndex)
        {
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;

            int    currentSectionElement   = 0;
            int    numberOfSectionElements = Element.Elements().Count();
            double invfac = numberOfSectionElements == 0 ? 1.0 : 1.0 / (double)numberOfSectionElements;

            foreach (XElement SectionElement in Element.Elements())
            {
                Plugin.CurrentProgress = Plugin.CurrentProgress + invfac * (double)currentSectionElement;
                if ((currentSectionElement & 4) == 0)
                {
                    System.Threading.Thread.Sleep(1);
                    if (Plugin.Cancel)
                    {
                        return;
                    }
                }

                string Section = SectionElement.Name.LocalName;

                switch (SectionElement.Name.LocalName.ToLowerInvariant())
                {
                case "group":
                    if (GroupIndex == 0)
                    {
                        int n = 0;

                        foreach (XElement KeyNode in SectionElement.Elements())
                        {
                            string Key        = KeyNode.Name.LocalName;
                            string Value      = KeyNode.Value;
                            int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                            switch (Key.ToLowerInvariant())
                            {
                            case "number":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out n))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;
                            }
                        }

                        if (n + 1 >= CarSection.Groups.Length)
                        {
                            Array.Resize(ref CarSection.Groups, n + 2);
                            CarSection.Groups[n + 1] = new ElementsGroup(ObjectType.Overlay);
                        }

                        ParsePanelAnimatedNode(SectionElement, FileName, TrainPath, Train, Car, CarSection, n + 1);
                    }
                    break;

                case "touch":
                    if (GroupIndex > 0)
                    {
                        Vector3             Position       = Vector3.Zero;
                        Vector3             Size           = Vector3.Zero;
                        int                 JumpScreen     = GroupIndex - 1;
                        List <int>          SoundIndices   = new List <int>();
                        List <CommandEntry> CommandEntries = new List <CommandEntry>();
                        CommandEntry        CommandEntry   = new CommandEntry();

                        foreach (XElement KeyNode in SectionElement.Elements())
                        {
                            string Key        = KeyNode.Name.LocalName;
                            string Value      = KeyNode.Value;
                            int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                            switch (Key.ToLowerInvariant())
                            {
                            case "position":
                                if (!Vector3.TryParse(KeyNode.Value, ',', out Position))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Position is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "size":
                                if (!Vector3.TryParse(KeyNode.Value, ',', out Size))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Size is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "jumpscreen":
                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out JumpScreen))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "soundindex":
                                if (Value.Length != 0)
                                {
                                    int SoundIndex;

                                    if (!NumberFormats.TryParseIntVb6(Value, out SoundIndex))
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                    }

                                    SoundIndices.Add(SoundIndex);
                                }
                                break;

                            case "command":
                            {
                                if (!CommandEntries.Contains(CommandEntry))
                                {
                                    CommandEntries.Add(CommandEntry);
                                }

                                if (string.Compare(Value, "N/A", StringComparison.InvariantCultureIgnoreCase) == 0)
                                {
                                    break;
                                }

                                int i;
                                for (i = 0; i < Translations.CommandInfos.Length; i++)
                                {
                                    if (string.Compare(Value, Translations.CommandInfos[i].Name, StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        break;
                                    }
                                }
                                if (i == Translations.CommandInfos.Length || Translations.CommandInfos[i].Type != Translations.CommandType.Digital)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                else
                                {
                                    CommandEntry.Command = Translations.CommandInfos[i].Command;
                                }
                            }
                            break;

                            case "commandoption":
                                if (!CommandEntries.Contains(CommandEntry))
                                {
                                    CommandEntries.Add(CommandEntry);
                                }

                                if (Value.Length != 0 && !NumberFormats.TryParseIntVb6(Value, out CommandEntry.Option))
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                                break;

                            case "soundentries":
                                if (!KeyNode.HasElements)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"An empty list of touch sound indices was defined at line {((IXmlLineInfo)KeyNode).LineNumber} in XML file {FileName}");
                                    break;
                                }

                                ParseTouchSoundEntryNode(FileName, KeyNode, SoundIndices);
                                break;

                            case "commandentries":
                                if (!KeyNode.HasElements)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, $"An empty list of touch commands was defined at line {((IXmlLineInfo)KeyNode).LineNumber} in XML file {FileName}");
                                    break;
                                }

                                ParseTouchCommandEntryNode(FileName, KeyNode, CommandEntries);
                                break;
                            }
                        }
                        CreateTouchElement(CarSection.Groups[GroupIndex], Position, Size, JumpScreen, SoundIndices.ToArray(), CommandEntries.ToArray());
                    }
                    break;

                case "include":
                {
                    foreach (XElement KeyNode in SectionElement.Elements())
                    {
                        string Key        = KeyNode.Name.LocalName;
                        string Value      = KeyNode.Value;
                        int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                        switch (Key.ToLowerInvariant())
                        {
                        case "filename":
                        {
                            string File = OpenBveApi.Path.CombineFile(TrainPath, Value);
                            if (System.IO.File.Exists(File))
                            {
                                System.Text.Encoding e = TextEncoding.GetSystemEncodingFromFile(File);
                                UnifiedObject        currentObject;
                                Plugin.currentHost.LoadObject(File, e, out currentObject);
                                var a = currentObject as AnimatedObjectCollection;
                                if (a != null)
                                {
                                    for (int i = 0; i < a.Objects.Length; i++)
                                    {
                                        Plugin.currentHost.CreateDynamicObject(ref a.Objects[i].internalObject);
                                    }
                                    CarSection.Groups[GroupIndex].Elements = a.Objects;
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "Value is invalid in " + Key + " in " + Section + " at line " + LineNumber.ToString(Culture) + " in " + FileName);
                                }
                            }
                        }
                        break;
                        }
                    }
                }
                break;
                }
            }
        }
Пример #25
0
        private void ParseTrainCommand(TrainCommand Command, string[] Arguments, int Index, Expression Expression, ref RouteData Data, bool PreviewOnly)
        {
            switch (Command)
            {
            case TrainCommand.Interval:
            {
                if (!PreviewOnly)
                {
                    List <double> intervals = new List <double>();
                    for (int k = 0; k < Arguments.Length; k++)
                    {
                        double o;
                        if (!NumberFormats.TryParseDoubleVb6(Arguments[k], out o))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Interval " + k.ToString(Culture) + " is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            continue;
                        }

                        if (o == 0)
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Interval " + k.ToString(Culture) + " must be non-zero in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            continue;
                        }

                        if (o > 43200 && Plugin.CurrentOptions.EnableBveTsHacks)
                        {
                            //Southern Blighton- Treston park has a runinterval of well over 24 hours, and there are likely others
                            //Discard this
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Interval " + k.ToString(Culture) + " is greater than 12 hours in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            continue;
                        }

                        if (o < 120 && Plugin.CurrentOptions.EnableBveTsHacks)
                        {
                            /*
                             * An AI train follows the same schedule / rules as the player train
                             * ==>
                             * x Waiting time before departure at the first station (30s to 1min is 'normal')
                             * x Time to accelerate to linespeed
                             * x Time to clear (as a minimum) the protecting signal on station exit
                             *
                             * When the runinterval is below ~2minutes, on large numbers of routes, this
                             * shows up as a train overlapping the player train (bad....)
                             */
                            o = 120;
                        }

                        intervals.Add(o);
                    }

                    intervals.Sort();
                    if (intervals.Count > 0)
                    {
                        CurrentRoute.PrecedingTrainTimeDeltas = intervals.ToArray();
                    }
                }
            }
            break;

            case TrainCommand.Velocity:
            {
                if (!PreviewOnly)
                {
                    double limit = 0.0;
                    if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseDoubleVb6(Arguments[0], out limit))
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Speed is invalid in Train.Velocity at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        limit = 0.0;
                    }

                    Plugin.CurrentOptions.PrecedingTrainSpeedLimit = limit <= 0.0 ? double.PositiveInfinity : Data.UnitOfSpeed * limit;
                }
            }
            break;

            case TrainCommand.Folder:
            case TrainCommand.File:
            {
                if (PreviewOnly)
                {
                    if (Arguments.Length < 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        if (Path.ContainsInvalidChars(Arguments[0]))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "FolderName contains illegal characters in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        }
                        else
                        {
                            Plugin.CurrentOptions.TrainName = Arguments[0];
                        }
                    }
                }
            }
            break;

            case TrainCommand.Run:
            case TrainCommand.Rail:
            {
                if (!PreviewOnly)
                {
                    if (Index < 0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RailTypeIndex is out of range in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        int val = 0;
                        if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out val))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RunSoundIndex is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            val = 0;
                        }

                        if (val < 0)
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RunSoundIndex is expected to be non-negative in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            val = 0;
                        }

                        if (Index >= Data.Structure.Run.Length)
                        {
                            Array.Resize(ref Data.Structure.Run, Index + 1);
                        }

                        Data.Structure.Run[Index] = val;
                    }
                }
            }
            break;

            case TrainCommand.Flange:
            {
                if (!PreviewOnly)
                {
                    if (Index < 0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "RailTypeIndex is out of range in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        int val = 0;
                        if (Arguments.Length >= 1 && Arguments[0].Length > 0 && !NumberFormats.TryParseIntVb6(Arguments[0], out val))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "FlangeSoundIndex is invalid in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            val = 0;
                        }

                        if (val < 0)
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "FlangeSoundIndex expected to be non-negative in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            val = 0;
                        }

                        if (Index >= Data.Structure.Flange.Length)
                        {
                            Array.Resize(ref Data.Structure.Flange, Index + 1);
                        }

                        Data.Structure.Flange[Index] = val;
                    }
                }
            }
            break;

            case TrainCommand.TimetableDay:
            {
                if (!PreviewOnly)
                {
                    if (Index < 0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "TimetableIndex is expected to be non-negative in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (Arguments.Length < 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        if (Path.ContainsInvalidChars(Arguments[0]))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "FileName " + Arguments[0] + " contains illegal characters in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        }
                        else
                        {
                            while (Index >= Data.TimetableDaytime.Length)
                            {
                                int n = Data.TimetableDaytime.Length;
                                Array.Resize(ref Data.TimetableDaytime, n << 1);
                                for (int i = n; i < Data.TimetableDaytime.Length; i++)
                                {
                                    Data.TimetableDaytime[i] = null;
                                }
                            }

                            string f = string.Empty;
                            if (!string.IsNullOrEmpty(TrainPath))
                            {
                                f = Path.CombineFile(TrainPath, Arguments[0]);
                            }

                            if (!System.IO.File.Exists(f))
                            {
                                f = Path.CombineFile(ObjectPath, Arguments[0]);
                            }

                            if (System.IO.File.Exists(f))
                            {
                                Plugin.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out Data.TimetableDaytime[Index]);
                            }
                            else
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "DaytimeTimetable " + Index + " with FileName " + Arguments[0] + " was not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            }
                        }
                    }
                }
            }
            break;

            case TrainCommand.TimetableNight:
            {
                if (!PreviewOnly)
                {
                    if (Index < 0)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, "TimetableIndex is expected to be non-negative in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else if (Arguments.Length < 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        if (Path.ContainsInvalidChars(Arguments[0]))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "FileName " + Arguments[0] + " contains illegal characters in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        }
                        else
                        {
                            while (Index >= Data.TimetableNighttime.Length)
                            {
                                int n = Data.TimetableNighttime.Length;
                                Array.Resize(ref Data.TimetableNighttime, n << 1);
                                for (int i = n; i < Data.TimetableNighttime.Length; i++)
                                {
                                    Data.TimetableNighttime[i] = null;
                                }
                            }

                            string f = string.Empty;
                            if (!string.IsNullOrEmpty(TrainPath))
                            {
                                f = Path.CombineFile(TrainPath, Arguments[0]);
                            }

                            if (!System.IO.File.Exists(f))
                            {
                                f = Path.CombineFile(ObjectPath, Arguments[0]);
                            }

                            if (System.IO.File.Exists(f))
                            {
                                Plugin.CurrentHost.RegisterTexture(f, new TextureParameters(null, null), out Data.TimetableNighttime[Index]);
                            }
                            else
                            {
                                Plugin.CurrentHost.AddMessage(MessageType.Error, false, "DaytimeTimetable " + Index + " with FileName " + Arguments[0] + " was not found in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                            }
                        }
                    }
                }
            }
            break;

            case TrainCommand.Destination:
            {
                if (!PreviewOnly)
                {
                    if (Arguments.Length < 1)
                    {
                        Plugin.CurrentHost.AddMessage(MessageType.Error, false, Command + " is expected to have one argument at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                    }
                    else
                    {
                        if (!NumberFormats.TryParseIntVb6(Arguments[0], out Plugin.CurrentOptions.InitialDestination))
                        {
                            Plugin.CurrentHost.AddMessage(MessageType.Error, false, "Destination is expected to be an Integer in " + Command + " at line " + Expression.Line.ToString(Culture) + ", column " + Expression.Column.ToString(Culture) + " in file " + Expression.File);
                        }
                    }
                }
            }
            break;
            }
        }
Пример #26
0
        /// <summary>Parses any command-line arguments passed to the main program</summary>
        /// <param name="Arguments">A string array of arguments</param>
        /// <param name="Result">The main dialog result (Used to launch)</param>
        internal static void ParseArguments(string[] Arguments, ref formMain.MainDialogResult Result)
        {
            if (Arguments.Length == 0)
            {
                return;
            }
            for (int i = 0; i < Arguments.Length; i++)
            {
                int equals = Arguments[i].IndexOf('=');
                if (@equals >= 0)
                {
                    string key   = Arguments[i].Substring(0, @equals).Trim().ToLowerInvariant();
                    string value = Arguments[i].Substring(@equals + 1).Trim();
                    switch (key)
                    {
                    case "/route":
                        Result.RouteFile = value;
                        switch (TextEncoding.GetEncodingFromFile(Result.RouteFile))
                        {
                        case TextEncoding.Encoding.Utf7:
                            Result.RouteEncoding = System.Text.Encoding.UTF7;
                            break;

                        case TextEncoding.Encoding.Utf8:
                            Result.RouteEncoding = System.Text.Encoding.UTF8;
                            break;

                        case TextEncoding.Encoding.Utf16Le:
                            Result.RouteEncoding = System.Text.Encoding.Unicode;
                            break;

                        case TextEncoding.Encoding.Utf16Be:
                            Result.RouteEncoding = System.Text.Encoding.BigEndianUnicode;
                            break;

                        case TextEncoding.Encoding.Utf32Le:
                            Result.RouteEncoding = System.Text.Encoding.UTF32;
                            break;

                        case TextEncoding.Encoding.Utf32Be:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(12001);
                            break;

                        case TextEncoding.Encoding.Shift_JIS:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(932);
                            break;

                        case TextEncoding.Encoding.Windows1252:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(1252);
                            break;

                        case TextEncoding.Encoding.Big5:
                            Result.RouteEncoding = System.Text.Encoding.GetEncoding(950);
                            break;

                        default:
                            Result.RouteEncoding = Encoding.Default;
                            break;
                        }
                        break;

                    case "/train":
                        Result.TrainFolder = value;
                        switch (TextEncoding.GetEncodingFromFile(Result.TrainFolder, "train.txt"))
                        {
                        case TextEncoding.Encoding.Utf8:
                            Result.TrainEncoding = System.Text.Encoding.UTF8;
                            break;

                        case TextEncoding.Encoding.Utf16Le:
                            Result.TrainEncoding = System.Text.Encoding.Unicode;
                            break;

                        case TextEncoding.Encoding.Utf16Be:
                            Result.TrainEncoding = System.Text.Encoding.BigEndianUnicode;
                            break;

                        case TextEncoding.Encoding.Utf32Le:
                            Result.TrainEncoding = System.Text.Encoding.UTF32;
                            break;

                        case TextEncoding.Encoding.Utf32Be:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(12001);
                            break;

                        case TextEncoding.Encoding.Shift_JIS:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(932);
                            break;

                        case TextEncoding.Encoding.Windows1252:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(1252);
                            break;

                        case TextEncoding.Encoding.Big5:
                            Result.TrainEncoding = System.Text.Encoding.GetEncoding(950);
                            break;

                        default:
                            Result.TrainEncoding = Encoding.Default;
                            break;
                        }
                        break;

                    case "/station":
                        Result.InitialStation = value;
                        break;

                    case "/time":
                        Interface.TryParseTime(value, out Result.StartTime);
                        break;

                    case "/ai":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.AIDriver = true;
                        }
                        break;

                    case "/fullscreen":
                        if (value.ToLowerInvariant() == "true" || value.ToLowerInvariant() == "1")
                        {
                            Result.FullScreen = true;
                        }
                        break;

                    case "/width":
                        NumberFormats.TryParseIntVb6(value, out Result.Width);
                        break;

                    case "/height":
                        NumberFormats.TryParseIntVb6(value, out Result.Height);
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// Function to parse train definition
        /// </summary>
        /// <param name="ObjectPath">Absolute path to the object folder of route data</param>
        /// <param name="FileName">The filename of the containing XML file</param>
        /// <param name="SectionElement">The XElement to parse</param>
        /// <param name="TrainDirectory">Absolute path to the train directory</param>
        /// <param name="ConsistReversed">Whether to reverse the train composition.</param>
        private static void ParseTrainNode(string ObjectPath, string FileName, XElement SectionElement, ref string TrainDirectory, ref bool ConsistReversed)
        {
            string Section = SectionElement.Name.LocalName;

            foreach (XElement KeyNode in SectionElement.Elements())
            {
                string Key        = KeyNode.Name.LocalName;
                string Value      = KeyNode.Value;
                int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                switch (Key.ToLowerInvariant())
                {
                case "directory":
                {
                    string TmpPath = OpenBveApi.Path.CombineDirectory(System.IO.Path.GetDirectoryName(FileName), Value);
                    if (!Directory.Exists(TmpPath))
                    {
                        TmpPath = OpenBveApi.Path.CombineFile(Program.FileSystem.InitialTrainFolder, Value);
                    }
                    if (!Directory.Exists(TmpPath))
                    {
                        TmpPath = OpenBveApi.Path.CombineFile(Program.FileSystem.TrainInstallationDirectory, Value);
                    }
                    if (!Directory.Exists(TmpPath))
                    {
                        TmpPath = OpenBveApi.Path.CombineFile(ObjectPath, Value);
                    }

                    if (!Directory.Exists(TmpPath))
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Directory was not found in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    }
                    else
                    {
                        TrainDirectory = TmpPath;
                    }
                }
                break;

                case "reversed":
                    if (Value.Any())
                    {
                        switch (Value.ToLowerInvariant())
                        {
                        case "true":
                            ConsistReversed = true;
                            break;

                        case "false":
                            ConsistReversed = false;
                            break;

                        default:
                        {
                            int n;

                            if (!NumberFormats.TryParseIntVb6(Value, out n))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                            }
                            else
                            {
                                ConsistReversed = Convert.ToBoolean(n);
                            }
                        }
                        break;
                        }
                    }
                    break;

                default:
                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    break;
                }
            }
        }
Пример #28
0
        /// <summary>Loads the sound set for a BVE4 or openBVE sound.cfg based train</summary>
        /// <param name="train">The train</param>
        /// <param name="FileName">The absolute on-disk path to the sound.cfg file</param>
        /// <param name="trainFolder">The absolute on-disk path to the train's folder</param>
        internal void Parse(string FileName, string trainFolder, TrainBase train)
        {
            //Default sound positions and radii

            //3D center of the car
            Vector3 center = Vector3.Zero;
            //Positioned to the left of the car, but centered Y & Z
            Vector3 left = new Vector3(-1.3, 0.0, 0.0);
            //Positioned to the right of the car, but centered Y & Z
            Vector3 right = new Vector3(1.3, 0.0, 0.0);
            //Positioned at the front of the car, centered X and Y
            Vector3 front = new Vector3(0.0, 0.0, 0.5 * train.Cars[train.DriverCar].Length);
            //Positioned at the position of the panel / 3D cab (Remember that the panel is just an object in the world...)
            Vector3 panel = new Vector3(train.Cars[train.DriverCar].Driver.X, train.Cars[train.DriverCar].Driver.Y, train.Cars[train.DriverCar].Driver.Z + 1.0);

            //Radius at which the sound is audible at full volume, presumably in m
            //TODO: All radii are much too small in external mode, but we can't change them by default.....

            Encoding Encoding = TextEncoding.GetSystemEncodingFromFile(FileName);

            // parse configuration file
            System.Globalization.CultureInfo Culture = System.Globalization.CultureInfo.InvariantCulture;
            List <string> Lines = System.IO.File.ReadAllLines(FileName, Encoding).ToList();

            for (int i = Lines.Count - 1; i >= 0; i--)
            {
                /*
                 * Strip comments and remove empty resulting lines etc.
                 *
                 * This fixes an error with some NYCTA content, which has
                 * a copyright notice instead of the file header specified....
                 */
                int j = Lines[i].IndexOf(';');
                if (j >= 0)
                {
                    Lines[i] = Lines[i].Substring(0, j).Trim(new char[] { });
                }
                else
                {
                    Lines[i] = Lines[i].Trim(new char[] { });
                }
                if (string.IsNullOrEmpty(Lines[i]))
                {
                    Lines.RemoveAt(i);
                }
            }

            if (Lines.Count == 0)
            {
                Plugin.currentHost.AddMessage(MessageType.Error, false, "Empty sound.cfg encountered in " + FileName + ".");
            }
            else if (string.Compare(Lines[0], "version 1.0", StringComparison.OrdinalIgnoreCase) != 0)
            {
                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid file format encountered in " + FileName + ". The first line is expected to be \"Version 1.0\".");
            }
            string[] MotorFiles = new string[] { };
            double   invfac     = Lines.Count == 0 ? 1.0 : 1.0 / Lines.Count;

            for (int i = 0; i < Lines.Count; i++)
            {
                Plugin.CurrentProgress = Plugin.CurrentProgress + invfac * i;
                if ((i & 7) == 0)
                {
                    System.Threading.Thread.Sleep(1);
                    if (Plugin.Cancel)
                    {
                        return;
                    }
                }
                switch (Lines[i].ToLowerInvariant())
                {
                case "[run]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    for (int c = 0; c < train.Cars.Length; c++)
                                    {
                                        if (train.Cars[c].Sounds.Run == null)
                                        {
                                            train.Cars[c].Sounds.Run = new Dictionary <int, CarSound>();
                                        }

                                        if (train.Cars[c].Sounds.Run.ContainsKey(k))
                                        {
                                            train.Cars[c].Sounds.Run[k] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        }
                                        else
                                        {
                                            train.Cars[c].Sounds.Run.Add(k, new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center));
                                        }
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "RunIndex must be greater than or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[flange]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    for (int c = 0; c < train.Cars.Length; c++)
                                    {
                                        if (train.Cars[c].Sounds.Flange.ContainsKey(k))
                                        {
                                            train.Cars[c].Sounds.Flange[k] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        }
                                        else
                                        {
                                            train.Cars[c].Sounds.Flange.Add(k, new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center));
                                        }
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "FlangeIndex must be greater than or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[motor]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    if (k >= MotorFiles.Length)
                                    {
                                        Array.Resize(ref MotorFiles, k + 1);
                                    }
                                    MotorFiles[k] = Path.CombineFile(trainFolder, b);
                                    if (!System.IO.File.Exists(MotorFiles[k]))
                                    {
                                        Plugin.currentHost.AddMessage(MessageType.Error, true, "File " + MotorFiles[k] + " does not exist at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        MotorFiles[k] = null;
                                    }
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "MotorIndex must be greater than or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[switch]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    switchIndex;
                            if (NumberFormats.TryParseIntVb6(a, out switchIndex))
                            {
                                if (switchIndex < 0)
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Error, false, "SwitchIndex must be greater than or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                    continue;
                                }
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    int n = train.Cars[c].FrontAxle.PointSounds.Length;
                                    if (switchIndex >= n)
                                    {
                                        Array.Resize(ref train.Cars[c].FrontAxle.PointSounds, switchIndex + 1);
                                        Array.Resize(ref train.Cars[c].RearAxle.PointSounds, switchIndex + 1);
                                        for (int h = n; h < switchIndex; h++)
                                        {
                                            train.Cars[c].FrontAxle.PointSounds[h] = new CarSound();
                                            train.Cars[c].RearAxle.PointSounds[h]  = new CarSound();
                                        }
                                    }
                                    Vector3 frontaxle = new Vector3(0.0, 0.0, train.Cars[c].FrontAxle.Position);
                                    Vector3 rearaxle  = new Vector3(0.0, 0.0, train.Cars[c].RearAxle.Position);
                                    train.Cars[c].FrontAxle.PointSounds[switchIndex] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, frontaxle);
                                    train.Cars[c].RearAxle.PointSounds[switchIndex]  = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, rearaxle);
                                }
                            }
                            else
                            {
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported index " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[brake]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "bc release high":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.AirHigh = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            case "bc release":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.Air = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            case "bc release full":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.AirZero = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            case "emergency":
                                train.Handles.EmergencyBrake.ApplicationSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                break;

                            case "emergencyrelease":
                                train.Handles.EmergencyBrake.ReleaseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                break;

                            case "bp decomp":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.Release = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, center);
                                }

                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[compressor]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            for (int c = 0; c < train.Cars.Length; c++)
                            {
                                if (train.Cars[c].CarBrake.brakeType == BrakeType.Main)
                                {
                                    switch (a.ToLowerInvariant())
                                    {
                                    case "attack":
                                        train.Cars[c].CarBrake.airCompressor.StartSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        break;

                                    case "loop":
                                        train.Cars[c].CarBrake.airCompressor.LoopSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        break;

                                    case "release":
                                        train.Cars[c].CarBrake.airCompressor.EndSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                        break;

                                    default:
                                        Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                        break;
                                    }
                                }
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[suspension]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "left":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Sounds.SpringL = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, left);
                                }

                                break;

                            case "right":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Sounds.SpringR = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, right);
                                }

                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[horn]":
                    i++;
                    while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            //PRIMARY HORN (Enter)
                            case "primarystart":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var primaryStart);
                                train.Cars[train.DriverCar].Horns[0].StartSound     = primaryStart as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[0].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[0].StartEndSounds = true;
                                break;

                            case "primaryend":
                            case "primaryrelease":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var primaryEnd);
                                train.Cars[train.DriverCar].Horns[0].EndSound       = primaryEnd as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[0].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[0].StartEndSounds = true;
                                break;

                            case "primaryloop":
                            case "primary":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var primaryLoop);
                                train.Cars[train.DriverCar].Horns[0].LoopSound     = primaryLoop as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[0].SoundPosition = front;
                                train.Cars[train.DriverCar].Horns[0].Loop          = false;
                                break;

                            //SECONDARY HORN (Numpad Enter)
                            case "secondarystart":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var secondaryStart);
                                train.Cars[train.DriverCar].Horns[1].StartSound     = secondaryStart as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[1].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[1].StartEndSounds = true;
                                break;

                            case "secondaryend":
                            case "secondaryrelease":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var secondaryEnd);
                                train.Cars[train.DriverCar].Horns[1].EndSound       = secondaryEnd as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[1].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[1].StartEndSounds = true;
                                break;

                            case "secondaryloop":
                            case "secondary":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.largeRadius, out var secondaryLoop);
                                train.Cars[train.DriverCar].Horns[1].LoopSound     = secondaryLoop as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[1].SoundPosition = front;
                                train.Cars[train.DriverCar].Horns[1].Loop          = false;
                                break;

                            //MUSIC HORN
                            case "musicstart":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.mediumRadius, out var musicStart);
                                train.Cars[train.DriverCar].Horns[2].StartSound     = musicStart as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[2].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[2].StartEndSounds = true;
                                break;

                            case "musicend":
                            case "musicrelease":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.mediumRadius, out var musicEnd);
                                train.Cars[train.DriverCar].Horns[2].EndSound       = musicEnd as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[2].SoundPosition  = front;
                                train.Cars[train.DriverCar].Horns[2].StartEndSounds = true;
                                break;

                            case "musicloop":
                            case "music":
                                Plugin.currentHost.RegisterSound(Path.CombineFile(trainFolder, b), SoundCfgParser.mediumRadius, out var musicLoop);
                                train.Cars[train.DriverCar].Horns[2].LoopSound     = musicLoop as SoundBuffer;
                                train.Cars[train.DriverCar].Horns[2].SoundPosition = front;
                                train.Cars[train.DriverCar].Horns[2].Loop          = true;
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[door]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "open left":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[0].OpenSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, left);
                                }

                                break;

                            case "open right":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[1].OpenSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, right);
                                }

                                break;

                            case "close left":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[0].CloseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, left);
                                }

                                break;

                            case "close right":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].Doors[1].CloseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, right);
                                }
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[ats]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            int    k;
                            if (!int.TryParse(a, System.Globalization.NumberStyles.Integer, Culture, out k))
                            {
                                Plugin.currentHost.AddMessage(MessageType.Error, false, "Invalid index appeared at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    int n = train.Cars[train.DriverCar].Sounds.Plugin.Length;
                                    if (k >= n)
                                    {
                                        Array.Resize(ref train.Cars[train.DriverCar].Sounds.Plugin, k + 1);
                                        for (int h = n; h < k; h++)
                                        {
                                            train.Cars[train.DriverCar].Sounds.Plugin[h] = new CarSound();
                                        }
                                    }

                                    train.Cars[train.DriverCar].Sounds.Plugin[k] = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                }
                                else
                                {
                                    Plugin.currentHost.AddMessage(MessageType.Warning, false, "Index must be greater than or equal to zero at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                }
                            }
                        }

                        i++;
                    }
                    i--; break;

                case "[buzzer]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "correct":
                                train.SafetySystems.StationAdjust.AdjustAlarm = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[pilot lamp]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "on":
                                train.SafetySystems.PilotLamp.OnSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "off":
                                train.SafetySystems.PilotLamp.OffSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[brake handle]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "apply":
                                train.Handles.Brake.Increase = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "applyfast":
                                train.Handles.Brake.IncreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "release":
                                train.Handles.Brake.Decrease = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "releasefast":
                                train.Handles.Brake.DecreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "min":
                                train.Handles.Brake.Min = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "max":
                                train.Handles.Brake.Max = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[master controller]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "up":
                                train.Handles.Power.Increase = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "upfast":
                                train.Handles.Power.IncreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "down":
                                train.Handles.Power.Decrease = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "downfast":
                                train.Handles.Power.DecreaseFast = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "min":
                                train.Handles.Power.Min = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "max":
                                train.Handles.Power.Max = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[reverser]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "on":
                                train.Handles.Reverser.EngageSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "off":
                                train.Handles.Reverser.ReleaseSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[breaker]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "on":
                                train.Cars[train.DriverCar].Breaker.Resume = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, panel);
                                break;

                            case "off":
                                train.Cars[train.DriverCar].Breaker.ResumeOrInterrupt = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.smallRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[others]":
                    i++;
                    while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "noise":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    if (train.Cars[c].Specs.IsMotorCar | c == train.DriverCar)
                                    {
                                        train.Cars[c].Sounds.Loop = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                    }
                                }

                                break;

                            case "shoe":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.Cars[c].CarBrake.Rub = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.mediumRadius, center);
                                }

                                break;

                            case "halt":
                                for (int c = 0; c < train.Cars.Length; c++)
                                {
                                    train.SafetySystems.PassAlarm.Sound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                }

                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;

                case "[windscreen]":
                    i++; while (i < Lines.Count && !Lines[i].StartsWith("[", StringComparison.Ordinal))
                    {
                        int j = Lines[i].IndexOf("=", StringComparison.Ordinal);
                        if (j >= 0)
                        {
                            string a = Lines[i].Substring(0, j).TrimEnd(new char[] { });
                            string b = Lines[i].Substring(j + 1).TrimStart(new char[] { });
                            switch (a.ToLowerInvariant())
                            {
                            case "raindrop":
                                train.Cars[train.DriverCar].Windscreen.DropSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "wetwipe":
                                train.Cars[train.DriverCar].Windscreen.Wipers.WetWipeSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "drywipe":
                                train.Cars[train.DriverCar].Windscreen.Wipers.DryWipeSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            case "switch":
                                train.Cars[train.DriverCar].Windscreen.Wipers.SwitchSound = new CarSound(Plugin.currentHost, trainFolder, FileName, i, b, SoundCfgParser.tinyRadius, panel);
                                break;

                            default:
                                Plugin.currentHost.AddMessage(MessageType.Warning, false, "Unsupported key " + a + " encountered at line " + (i + 1).ToString(Culture) + " in file " + FileName);
                                break;
                            }
                        }
                        i++;
                    }
                    i--; break;
                }
            }
            // motor sound
            for (int c = 0; c < train.Cars.Length; c++)
            {
                if (train.Cars[c].Specs.IsMotorCar)
                {
                    train.Cars[c].Sounds.Motor.Position = center;
                    for (int i = 0; i < train.Cars[c].Sounds.Motor.Tables.Length; i++)
                    {
                        train.Cars[c].Sounds.Motor.Tables[i].Buffer = null;
                        train.Cars[c].Sounds.Motor.Tables[i].Source = null;
                        for (int j = 0; j < train.Cars[c].Sounds.Motor.Tables[i].Entries.Length; j++)
                        {
                            int index = train.Cars[c].Sounds.Motor.Tables[i].Entries[j].SoundIndex;
                            if (index >= 0 && index < MotorFiles.Length && MotorFiles[index] != null)
                            {
                                Plugin.currentHost.RegisterSound(MotorFiles[index], SoundCfgParser.mediumRadius, out var motorSound);
                                train.Cars[c].Sounds.Motor.Tables[i].Entries[j].Buffer = motorSound as SoundBuffer;
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Function to parse the contents of TravelStopData class
        /// </summary>
        /// <param name="FileName">The filename of the containing XML file</param>
        /// <param name="SectionElement">The XElement to parse</param>
        /// <returns>An instance of the new TravelStopData class with the parse result applied</returns>
        private static TravelStopData ParseTravelStopNode(string FileName, XElement SectionElement)
        {
            string Section = SectionElement.Name.LocalName;

            TravelStopData Data = new TravelStopData();

            ParseTravelDataNode(FileName, SectionElement, Data);

            foreach (XElement KeyNode in SectionElement.Elements())
            {
                string Key        = KeyNode.Name.LocalName;
                string Value      = KeyNode.Value;
                int    LineNumber = ((IXmlLineInfo)KeyNode).LineNumber;

                switch (Key.ToLowerInvariant())
                {
                case "stoptime":
                    if (Value.Any() && !Interface.TryParseTime(Value, out Data.StopTime))
                    {
                        Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    }
                    break;

                case "doors":
                {
                    int  Door     = 0;
                    bool DoorBoth = false;

                    switch (Value.ToLowerInvariant())
                    {
                    case "l":
                    case "left":
                        Door = -1;
                        break;

                    case "r":
                    case "right":
                        Door = 1;
                        break;

                    case "n":
                    case "none":
                    case "neither":
                        Door = 0;
                        break;

                    case "b":
                    case "both":
                        DoorBoth = true;
                        break;

                    default:
                        if (Value.Any() && !NumberFormats.TryParseIntVb6(Value, out Door))
                        {
                            Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                        }
                        break;
                    }

                    Data.OpenLeftDoors  = Door < 0.0 | DoorBoth;
                    Data.OpenRightDoors = Door > 0.0 | DoorBoth;
                }
                break;

                case "direction":
                {
                    int d = 0;
                    switch (Value.ToLowerInvariant())
                    {
                    case "f":
                        d = 1;
                        break;

                    case "r":
                        d = -1;
                        break;

                    default:
                        if (Value.Any() && (!NumberFormats.TryParseIntVb6(Value, out d) || !Enum.IsDefined(typeof(TravelDirection), d)))
                        {
                            Interface.AddMessage(MessageType.Error, false, $"Value is invalid in {Key} in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                            d = 1;
                        }
                        break;
                    }

                    Data.Direction = (TravelDirection)d;
                }
                break;

                case "decelerate":
                case "position":
                case "stopposition":
                case "accelerate":
                case "targetspeed":
                case "rail":
                    // Already parsed
                    break;

                default:
                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {Key} encountered in {Section} at line {LineNumber.ToString(culture)} in {FileName}");
                    break;
                }
            }

            return(Data);
        }
Пример #30
0
        /// <summary>Loads a list of compatibility signal objects</summary>
        /// <param name="currentHost">The host application interface</param>
        /// <param name="fileName">The file name of the object list</param>
        /// <param name="objects">The returned array of speed limits</param>
        /// <param name="signalPost">Sets the default signal post</param>
        /// <param name="speedLimits">The array of signal speed limits</param>
        /// <returns>An array of compatability signal objects</returns>
        public static void ReadCompatibilitySignalXML(HostInterface currentHost, string fileName, out CompatibilitySignalObject[] objects, out UnifiedObject signalPost, out double[] speedLimits)
        {
            signalPost = new StaticObject(currentHost);
            objects    = new CompatibilitySignalObject[9];
            //Default Japanese speed limits converted to m/s
            speedLimits = new[] { 0.0, 6.94444444444444, 15.2777777777778, 20.8333333333333, double.PositiveInfinity, double.PositiveInfinity };
            XmlDocument currentXML = new XmlDocument();

            currentXML.Load(fileName);
            string currentPath = System.IO.Path.GetDirectoryName(fileName);

            if (currentXML.DocumentElement != null)
            {
                XmlNode node = currentXML.SelectSingleNode("/openBVE/CompatibilitySignals/SignalSetName");
                if (node != null)
                {
                    currentHost.AddMessage(MessageType.Information, false, "INFO: Using the " + node.InnerText + " compatibility signal set.");
                }
                XmlNodeList DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/CompatibilitySignals/Signal");
                if (DocumentNodes != null)
                {
                    int index = 0;
                    foreach (XmlNode nn in DocumentNodes)
                    {
                        List <StaticObject> objectList = new List <StaticObject>();
                        List <int>          aspectList = new List <int>();
                        try
                        {
                            if (nn.HasChildNodes)
                            {
                                foreach (XmlNode n in nn.ChildNodes)
                                {
                                    if (n.Name != "Aspect")
                                    {
                                        continue;
                                    }

                                    int aspect = 0;
                                    if (!NumberFormats.TryParseIntVb6(n.Attributes["Number"].Value, out aspect))
                                    {
                                        currentHost.AddMessage(MessageType.Error, true, "Invalid aspect number " + aspect + " in the signal object list in the compatability signal file " + fileName);
                                        continue;
                                    }

                                    aspectList.Add(aspect);

                                    StaticObject staticObject = new StaticObject(currentHost);
                                    if (n.InnerText.ToLowerInvariant() != "null")
                                    {
                                        string objectFile = Path.CombineFile(currentPath, n.InnerText);
                                        if (File.Exists(objectFile))
                                        {
                                            currentHost.LoadStaticObject(objectFile, Encoding.UTF8, false, out staticObject);
                                        }
                                        else
                                        {
                                            currentHost.AddMessage(MessageType.Error, true, "Compatibility signal file " + objectFile + " not found in " + fileName);
                                        }
                                    }
                                    objectList.Add(staticObject);
                                }
                            }
                        }
                        catch
                        {
                            currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName);
                        }
                        objects[index] = new CompatibilitySignalObject(aspectList.ToArray(), objectList.ToArray());
                        index++;
                    }
                }

                string signalPostFile = Path.CombineFile(currentPath, "Japanese\\signal_post.csv");                 //default plain post
                try
                {
                    node = currentXML.SelectSingleNode("/openBVE/CompatibilitySignals/SignalPost");
                    if (node != null)
                    {
                        string newFile = Path.CombineFile(currentPath, node.InnerText);
                        if (System.IO.File.Exists(newFile))
                        {
                            signalPostFile = newFile;
                        }
                    }
                    currentHost.LoadObject(signalPostFile, Encoding.UTF8, out signalPost);
                }
                catch
                {
                    currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName);
                }

                DocumentNodes = currentXML.DocumentElement.SelectNodes("/openBVE/CompatibilitySignals/SpeedLimits");
                if (DocumentNodes != null)
                {
                    foreach (XmlNode nn in DocumentNodes)
                    {
                        try
                        {
                            if (nn.HasChildNodes)
                            {
                                foreach (XmlNode n in nn.ChildNodes)
                                {
                                    if (n.Name != "Aspect")
                                    {
                                        continue;
                                    }

                                    int aspect = 0;
                                    if (n.Attributes != null)
                                    {
                                        if (!NumberFormats.TryParseIntVb6(n.Attributes["Number"].Value, out aspect))
                                        {
                                            currentHost.AddMessage(MessageType.Error, true, "Invalid aspect number " + aspect + " in the speed limit list in the compatability signal file " + fileName);
                                            continue;
                                        }
                                    }

                                    if (aspect <= speedLimits.Length)
                                    {
                                        int l = speedLimits.Length;
                                        Array.Resize(ref speedLimits, aspect + 1);
                                        for (int i = l; i < speedLimits.Length; i++)
                                        {
                                            speedLimits[i] = double.PositiveInfinity;
                                        }

                                        if (!NumberFormats.TryParseDoubleVb6(n.InnerText, out speedLimits[aspect]))
                                        {
                                            speedLimits[aspect] = double.MaxValue;
                                            if (n.InnerText.ToLowerInvariant() != "unlimited")
                                            {
                                                currentHost.AddMessage(MessageType.Error, true, "Invalid speed limit provided for aspect " + aspect + " in the compatability signal file " + fileName);
                                            }
                                        }
                                        else
                                        {
                                            //convert to m/s as that's what we use internally
                                            speedLimits[aspect] *= 0.277777777777778;
                                        }
                                    }
                                }
                            }
                        }
                        catch
                        {
                            currentHost.AddMessage(MessageType.Error, true, "An unexpected error was encountered whilst processing the compatability signal file " + fileName);
                        }
                    }
                }
            }
        }