private static void ParseExtensionsConfig(string filePath, Encoding encoding, out UnifiedObject[] carObjects, out UnifiedObject[] bogieObjects, out UnifiedObject[] couplerObjects, out double[] axleLocations, out double[] couplerDistances, out TrainManager.Train train, bool loadObjects)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

            carObjects       = new UnifiedObject[0];
            bogieObjects     = new UnifiedObject[0];
            couplerObjects   = new UnifiedObject[0];
            axleLocations    = new double[0];
            couplerDistances = new double[0];
            train            = new TrainManager.Train {
                Cars = new TrainManager.Car[0]
            };

            if (!File.Exists(filePath))
            {
                return;
            }

            bool[] carObjectsReversed   = new bool[0];
            bool[] bogieObjectsReversed = new bool[0];
            bool[] carsDefined          = new bool[0];
            bool[] bogiesDefined        = new bool[0];
            bool[] couplerDefined       = new bool[0];

            string trainPath = System.IO.Path.GetDirectoryName(filePath);

            if (encoding == null)
            {
                encoding = TextEncoding.GetSystemEncodingFromFile(trainPath);
            }

            string[] lines = File.ReadAllLines(filePath, encoding);
            for (int i = 0; i < lines.Length; i++)
            {
                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[] { });
                }
            }

            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i].Length != 0)
                {
                    switch (lines[i].ToLowerInvariant())
                    {
                    case "[exterior]":
                        // exterior
                        i++;
                        while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            if (lines[i].Length != 0)
                            {
                                int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                if (j >= 0)
                                {
                                    // ReSharper disable RedundantExplicitParamsArrayCreation
                                    string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                    string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                    // ReSharper restore RedundantExplicitParamsArrayCreation

                                    int n;
                                    if (int.TryParse(a, NumberStyles.Integer, culture, out n))
                                    {
                                        if (n >= 0)
                                        {
                                            if (n >= train.Cars.Length)
                                            {
                                                Array.Resize(ref train.Cars, n + 1);
                                                train.Cars[n] = new TrainManager.Car(train);
                                                Array.Resize(ref carObjects, n + 1);
                                                Array.Resize(ref bogieObjects, (n + 1) * 2);
                                                Array.Resize(ref couplerObjects, n);
                                                Array.Resize(ref carObjectsReversed, n + 1);
                                                Array.Resize(ref bogieObjectsReversed, (n + 1) * 2);
                                                Array.Resize(ref carsDefined, n + 1);
                                                Array.Resize(ref bogiesDefined, (n + 1) * 2);
                                                Array.Resize(ref couplerDefined, n);
                                                Array.Resize(ref axleLocations, (n + 1) * 2);
                                                Array.Resize(ref couplerDistances, n);
                                            }
                                            if (Path.ContainsInvalidChars(b))
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                            else
                                            {
                                                string file = Path.CombineFile(trainPath, b);
                                                if (File.Exists(file))
                                                {
                                                    if (loadObjects)
                                                    {
                                                        Program.CurrentHost.LoadObject(file, encoding, out carObjects[n]);
                                                    }
                                                }
                                                else
                                                {
                                                    Interface.AddMessage(MessageType.Error, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                }
                                            }
                                        }
                                        else
                                        {
                                            Interface.AddMessage(MessageType.Error, false, $"The car index {a} does not reference an existing car at line {(i + 1).ToString(culture)} in file {filePath}");
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            i++;
                        }
                        i--;
                        break;

                    default:
                        if (lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // car
                            string t = lines[i].Substring(4, lines[i].Length - 5);
                            int    n;
                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    if (n >= train.Cars.Length)
                                    {
                                        Array.Resize(ref train.Cars, n + 1);
                                        train.Cars[n] = new TrainManager.Car(train);
                                        Array.Resize(ref carObjects, n + 1);
                                        Array.Resize(ref bogieObjects, (n + 1) * 2);
                                        Array.Resize(ref carObjectsReversed, n + 1);
                                        Array.Resize(ref bogieObjectsReversed, (n + 1) * 2);
                                        Array.Resize(ref couplerObjects, n);
                                        Array.Resize(ref carsDefined, n + 1);
                                        Array.Resize(ref bogiesDefined, (n + 1) * 2);
                                        Array.Resize(ref couplerDefined, n);
                                        Array.Resize(ref axleLocations, (n + 1) * 2);
                                        Array.Resize(ref couplerDistances, n);
                                    }
                                    if (carsDefined[n])
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"Car {n.ToString(culture)} has already been declared at line {(i + 1).ToString(culture)} in file {filePath}");
                                    }
                                    carsDefined[n] = true;
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                // ReSharper disable RedundantExplicitParamsArrayCreation
                                                string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                // ReSharper restore RedundantExplicitParamsArrayCreation

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty car object was supplied at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        break;
                                                    }
                                                    if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(trainPath, b);
                                                        if (File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                Program.CurrentHost.LoadObject(file, encoding, out carObjects[n]);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    break;

                                                case "length":
                                                {
                                                    double m;
                                                    if (double.TryParse(b, NumberStyles.Float, culture, out m))
                                                    {
                                                        if (m > 0.0)
                                                        {
                                                            train.Cars[n].Length = m;
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                }
                                                break;

                                                case "reversed":
                                                    carObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                case "axles":
                                                    int k = b.IndexOf(',');
                                                    if (k >= 0)
                                                    {
                                                        // ReSharper disable RedundantExplicitParamsArrayCreation
                                                        string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                        string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                        // ReSharper restore RedundantExplicitParamsArrayCreation

                                                        double rear, front;
                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out rear))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out front))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Front is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (rear >= front)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be less than Front in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else
                                                        {
                                                            if (n == 0)
                                                            {
                                                                axleLocations[n]     = rear;
                                                                axleLocations[n + 1] = front;
                                                            }
                                                            else
                                                            {
                                                                axleLocations[n * 2]     = rear;
                                                                axleLocations[n * 2 + 1] = front;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                        }
                                        i++;
                                    }
                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The car index {t} does not reference an existing car at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                            }
                        }
                        else if (lines[i].StartsWith("[bogie", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // bogie
                            string t = lines[i].Substring(6, lines[i].Length - 7);
                            int    n;
                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= train.Cars.Length * 2)
                                {
                                    Array.Resize(ref train.Cars, n / 2 + 1);
                                    if (n == 0)
                                    {
                                        train.Cars[0] = new TrainManager.Car(train);
                                        Array.Resize(ref axleLocations, 2);
                                    }
                                    else
                                    {
                                        train.Cars[n / 2] = new TrainManager.Car(train);
                                        Array.Resize(ref axleLocations, (n / 2 + 1) * 2);
                                    }

                                    Array.Resize(ref carObjects, n / 2 + 1);
                                    Array.Resize(ref bogieObjects, n + 2);
                                    Array.Resize(ref couplerObjects, n / 2);
                                    Array.Resize(ref carObjectsReversed, n / 2 + 1);
                                    Array.Resize(ref bogieObjectsReversed, n + 2);
                                    Array.Resize(ref carsDefined, n / 2 + 1);
                                    Array.Resize(ref bogiesDefined, n + 2);
                                    Array.Resize(ref couplerDefined, n / 2);
                                    Array.Resize(ref couplerDistances, n / 2);
                                }

                                if (n > bogiesDefined.Length - 1)
                                {
                                    continue;
                                }
                                if (bogiesDefined[n])
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Bogie {n.ToString(culture)} has already been declared at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                                bogiesDefined[n] = true;
                                //Assuming that there are two bogies per car
                                if (n >= 0 & n < train.Cars.Length * 2)
                                {
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                // ReSharper disable RedundantExplicitParamsArrayCreation
                                                string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                // ReSharper restore RedundantExplicitParamsArrayCreation

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    else
                                                    {
                                                        if (string.IsNullOrEmpty(b))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"An empty bogie object was supplied at line {(i + 1).ToString(culture)} in file {filePath}");
                                                            break;
                                                        }
                                                        string file = Path.CombineFile(trainPath, b);
                                                        if (File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                Program.CurrentHost.LoadObject(file, encoding, out bogieObjects[n]);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"The bogie object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    break;

                                                case "length":
                                                {
                                                    Interface.AddMessage(MessageType.Error, false, $"A defined length is not supported for bogies at line {(i + 1).ToString(culture)} in file {filePath}");
                                                }
                                                break;

                                                case "reversed":
                                                    bogieObjectsReversed[n] = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                case "axles":
                                                    //Axles aren't used in bogie positioning, just in rotation
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                        }
                                        i++;
                                    }
                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The bogie index {t} does not reference an existing bogie at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The bogie index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                            }
                        }
                        else if (lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // coupler
                            string t = lines[i].Substring(8, lines[i].Length - 9);
                            int    n;
                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    if (n >= train.Cars.Length - 1)
                                    {
                                        Array.Resize(ref train.Cars, n + 2);
                                        train.Cars[n + 1] = new TrainManager.Car(train);
                                        Array.Resize(ref carObjects, n + 2);
                                        Array.Resize(ref bogieObjects, (n + 2) * 2);
                                        Array.Resize(ref carObjectsReversed, n + 2);
                                        Array.Resize(ref bogieObjectsReversed, (n + 2) * 2);
                                        Array.Resize(ref couplerObjects, n + 1);
                                        Array.Resize(ref carsDefined, n + 2);
                                        Array.Resize(ref bogiesDefined, (n + 2) * 2);
                                        Array.Resize(ref couplerDefined, n + 1);
                                        Array.Resize(ref axleLocations, (n + 2) * 2);
                                        Array.Resize(ref couplerDistances, n + 1);
                                    }
                                    if (couplerDefined[n])
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"Coupler {n.ToString(culture)} has already been declared at line {(i + 1).ToString(culture)} in file {filePath}");
                                    }
                                    couplerDefined[n] = true;
                                    i++;
                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Length != 0)
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);
                                            if (j >= 0)
                                            {
                                                // ReSharper disable RedundantExplicitParamsArrayCreation
                                                string a = lines[i].Substring(0, j).TrimEnd(new char[] { });
                                                string b = lines[i].Substring(j + 1).TrimStart(new char[] { });
                                                // ReSharper restore RedundantExplicitParamsArrayCreation

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "distances":
                                                {
                                                    int k = b.IndexOf(',');
                                                    if (k >= 0)
                                                    {
                                                        // ReSharper disable RedundantExplicitParamsArrayCreation
                                                        string c = b.Substring(0, k).TrimEnd(new char[] { });
                                                        string d = b.Substring(k + 1).TrimStart(new char[] { });
                                                        // ReSharper restore RedundantExplicitParamsArrayCreation

                                                        double min, max;
                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out min))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out max))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Maximum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else if (min > max)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be less than Maximum in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                        else
                                                        {
                                                            couplerDistances[n] = 0.5 * (min + max);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                }
                                                break;

                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty coupler object was supplied at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        break;
                                                    }
                                                    if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(trainPath, b);
                                                        if (File.Exists(file))
                                                        {
                                                            if (loadObjects)
                                                            {
                                                                Program.CurrentHost.LoadObject(file, encoding, out couplerObjects[n]);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, true, $"The coupler object {file} does not exist at line {(i + 1).ToString(culture)} in file {filePath}");
                                                        }
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                                            }
                                        }
                                        i++;
                                    }
                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The coupler index {t} does not reference an existing coupler at line {(i + 1).ToString(culture)} in file {filePath}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The coupler index is expected to be an integer at line {(i + 1).ToString(culture)} in file {filePath}");
                            }
                        }
                        else
                        {
                            // default
                            if (lines.Length == 1 && encoding.Equals(Encoding.Unicode))
                            {
                                /*
                                 * If only one line, there's a good possibility that our file is NOT Unicode at all
                                 * and that the misdetection has turned it into garbage
                                 *
                                 * Try again with ASCII instead
                                 */
                                ParseExtensionsConfig(filePath, Encoding.GetEncoding(1252), out carObjects, out bogieObjects, out couplerObjects, out axleLocations, out couplerDistances, out train, loadObjects);
                                return;
                            }
                            Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {filePath}");
                        }
                        break;
                    }
                }
            }

            // check for car objects and reverse if necessary
            int carObjectsCount = 0;

            for (int i = 0; i < train.Cars.Length; i++)
            {
                if (carObjects[i] != null)
                {
                    carObjectsCount++;
                    if (carObjectsReversed[i] && loadObjects)
                    {
                        if (carObjects[i] is StaticObject)
                        {
                            StaticObject obj = (StaticObject)carObjects[i];
                            obj.ApplyScale(-1.0, 1.0, -1.0);
                        }
                        else if (carObjects[i] is AnimatedObjectCollection)
                        {
                            AnimatedObjectCollection obj = (AnimatedObjectCollection)carObjects[i];
                            foreach (AnimatedObject animatedObj in obj.Objects)
                            {
                                foreach (ObjectState state in animatedObj.States)
                                {
                                    state.Prototype.ApplyScale(-1.0, 1.0, -1.0);
                                    Matrix4D t = state.Translation;
                                    t.Row3.X         *= -1.0f;
                                    t.Row3.Z         *= -1.0f;
                                    state.Translation = t;
                                }
                                animatedObj.TranslateXDirection.X *= -1.0;
                                animatedObj.TranslateXDirection.Z *= -1.0;
                                animatedObj.TranslateYDirection.X *= -1.0;
                                animatedObj.TranslateYDirection.Z *= -1.0;
                                animatedObj.TranslateZDirection.X *= -1.0;
                                animatedObj.TranslateZDirection.Z *= -1.0;
                            }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }
                }
            }

            //Check for bogie objects and reverse if necessary.....
            int bogieObjectsCount = 0;

            for (int i = 0; i < train.Cars.Length * 2; i++)
            {
                if (bogieObjects[i] != null)
                {
                    bogieObjectsCount++;
                    if (bogieObjectsReversed[i] && loadObjects)
                    {
                        if (bogieObjects[i] is StaticObject)
                        {
                            StaticObject obj = (StaticObject)bogieObjects[i];
                            obj.ApplyScale(-1.0, 1.0, -1.0);
                        }
                        else if (bogieObjects[i] is AnimatedObjectCollection)
                        {
                            AnimatedObjectCollection obj = (AnimatedObjectCollection)bogieObjects[i];
                            foreach (AnimatedObject animatedObj in obj.Objects)
                            {
                                foreach (ObjectState state in animatedObj.States)
                                {
                                    state.Prototype.ApplyScale(-1.0, 1.0, -1.0);
                                    Matrix4D t = state.Translation;
                                    t.Row3.X         *= -1.0f;
                                    t.Row3.Z         *= -1.0f;
                                    state.Translation = t;
                                }
                                animatedObj.TranslateXDirection.X *= -1.0;
                                animatedObj.TranslateXDirection.Z *= -1.0;
                                animatedObj.TranslateYDirection.X *= -1.0;
                                animatedObj.TranslateYDirection.Z *= -1.0;
                                animatedObj.TranslateZDirection.X *= -1.0;
                                animatedObj.TranslateZDirection.Z *= -1.0;
                            }
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }
                    }
                }
            }

            if (carObjectsCount > 0 & carObjectsCount < train.Cars.Length)
            {
                Interface.AddMessage(MessageType.Warning, false, $"An incomplete set of exterior objects was provided in file {filePath}");
            }

            if (bogieObjectsCount > 0 & bogieObjectsCount < train.Cars.Length * 2)
            {
                Interface.AddMessage(MessageType.Warning, false, $"An incomplete set of bogie objects was provided in file {filePath}");
            }
        }
Exemple #2
0
        internal static void Parse(string fileName, out Sound sound)
        {
            sound = new Sound();

            CultureInfo   culture  = CultureInfo.InvariantCulture;
            List <string> lines    = File.ReadAllLines(fileName, TextEncoding.GetSystemEncodingFromFile(fileName)).ToList();
            string        basePath = System.IO.Path.GetDirectoryName(fileName);

            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();
                }
                else
                {
                    lines[i] = lines[i].Trim();
                }

                if (string.IsNullOrEmpty(lines[i]))
                {
                    lines.RemoveAt(i);
                }
            }

            if (!lines.Any())
            {
                Interface.AddMessage(MessageType.Error, false, $"Empty sound.cfg encountered in {fileName}.");
            }

            if (string.Compare(lines[0], "version 1.0", StringComparison.OrdinalIgnoreCase) != 0)
            {
                Interface.AddMessage(MessageType.Error, false, $"Invalid file format encountered in {fileName}. The first line is expected to be \"Version 1.0\".");
            }

            for (int i = 0; i < lines.Count; i++)
            {
                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();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new RunElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index must be greater 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();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new FlangeElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index must be greater 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();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new MotorElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index is invalid 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();
                            string b = lines[i].Substring(j + 1).TrimStart();
                            int    k;

                            if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                if (k >= 0)
                                {
                                    sound.SoundElements.Add(new FrontSwitchElement {
                                        Key = k, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Index is invalid 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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BrakeKey[] keys = Enum.GetValues(typeof(BrakeKey)).OfType <BrakeKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BrakeElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                CompressorKey[] keys = Enum.GetValues(typeof(CompressorKey)).OfType <CompressorKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new CompressorElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                SuspensionKey[] keys = Enum.GetValues(typeof(SuspensionKey)).OfType <SuspensionKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new SuspensionElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                HornKey[] primaryKeys   = Enum.GetValues(typeof(HornKey)).OfType <HornKey>().Where(x => x.GetStringValues().Any(y => $"Primary{y}".Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();
                                HornKey[] secondaryKeys = Enum.GetValues(typeof(HornKey)).OfType <HornKey>().Where(x => x.GetStringValues().Any(y => $"Secondary{y}".Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();
                                HornKey[] musicKeys     = Enum.GetValues(typeof(HornKey)).OfType <HornKey>().Where(x => x.GetStringValues().Any(y => $"Music{y}".Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (primaryKeys.Any())
                                {
                                    sound.SoundElements.Add(new PrimaryHornElement {
                                        Key = primaryKeys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if (secondaryKeys.Any())
                                {
                                    sound.SoundElements.Add(new SecondaryHornElement {
                                        Key = secondaryKeys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if (musicKeys.Any())
                                {
                                    sound.SoundElements.Add(new MusicHornElement {
                                        Key = musicKeys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if ("Primary".Equals(a, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    sound.SoundElements.Add(new PrimaryHornElement {
                                        Key = HornKey.Loop, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if ("Secondary".Equals(a, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    sound.SoundElements.Add(new SecondaryHornElement {
                                        Key = HornKey.Loop, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else if ("Music".Equals(a, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    sound.SoundElements.Add(new MusicHornElement {
                                        Key = HornKey.Loop, FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                DoorKey[] keys = Enum.GetValues(typeof(DoorKey)).OfType <DoorKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new DoorElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                int k;

                                if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                                else
                                {
                                    if (k >= 0)
                                    {
                                        sound.SoundElements.Add(new AtsElement {
                                            Key = k, FilePath = Path.CombineFile(basePath, b)
                                        });
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Index must be greater 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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BuzzerKey[] keys = Enum.GetValues(typeof(BuzzerKey)).OfType <BuzzerKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BuzzerElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                PilotLampKey[] keys = Enum.GetValues(typeof(PilotLampKey)).OfType <PilotLampKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new PilotLampElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BrakeHandleKey[] keys = Enum.GetValues(typeof(BrakeHandleKey)).OfType <BrakeHandleKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BrakeHandleElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                MasterControllerKey[] keys = Enum.GetValues(typeof(MasterControllerKey)).OfType <MasterControllerKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new MasterControllerElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                ReverserKey[] keys = Enum.GetValues(typeof(ReverserKey)).OfType <ReverserKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new ReverserElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                BreakerKey[] keys = Enum.GetValues(typeof(BreakerKey)).OfType <BreakerKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new BreakerElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                OthersKey[] keys = Enum.GetValues(typeof(OthersKey)).OfType <OthersKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new OthersElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[requeststop]":
                    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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                RequestStopKey[] keys = Enum.GetValues(typeof(RequestStopKey)).OfType <RequestStopKey>().Where(x => x.GetStringValues().Any(y => y.Equals(a, StringComparison.InvariantCultureIgnoreCase))).ToArray();

                                if (keys.Any())
                                {
                                    sound.SoundElements.Add(new RequestStopElement {
                                        Key = keys.First(), FilePath = Path.CombineFile(basePath, b)
                                    });
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;

                case "[touch]":
                    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();
                            string b = lines[i].Substring(j + 1).TrimStart();

                            if (b.Length == 0 || Path.ContainsInvalidChars(b))
                            {
                                Interface.AddMessage(MessageType.Error, false, $"FileName contains illegal characters or is empty at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                            else
                            {
                                int k;

                                if (!int.TryParse(a, NumberStyles.Integer, culture, out k))
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid index appeared at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                                else
                                {
                                    if (k >= 0)
                                    {
                                        sound.SoundElements.Add(new TouchElement {
                                            Key = k, FilePath = Path.CombineFile(basePath, b)
                                        });
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Warning, false, "Index must be greater or equal to zero at line " + (i + 1).ToString(culture) + " in file " + fileName);
                                    }
                                }
                            }
                        }

                        i++;
                    }

                    i--;
                    break;
                }
            }

            sound.SoundElements = new ObservableCollection <SoundElement>(sound.SoundElements.GroupBy(x => new { Type = x.GetType(), x.Key }).Select(x => x.First()));
        }
Exemple #3
0
        internal static void Parse(string fileName, Train train)
        {
            CultureInfo culture = CultureInfo.InvariantCulture;

            string[] lines = File.ReadAllLines(fileName, TextEncoding.GetSystemEncodingFromFile(fileName));

            for (int i = 0; i < lines.Length; i++)
            {
                int j = lines[i].IndexOf(';');

                if (j >= 0)
                {
                    lines[i] = lines[i].Substring(0, j).Trim();
                }
                else
                {
                    lines[i] = lines[i].Trim();
                }
            }

            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i].Any())
                {
                    switch (lines[i].ToLowerInvariant())
                    {
                    case "[exterior]":
                        i++;

                        while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            if (lines[i].Any())
                            {
                                int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                if (j >= 0)
                                {
                                    string a = lines[i].Substring(0, j).TrimEnd();
                                    string b = lines[i].Substring(j + 1).TrimStart();
                                    int    n;

                                    if (int.TryParse(a, NumberStyles.Integer, culture, out n))
                                    {
                                        if (n >= 0)
                                        {
                                            for (int k = n; k >= train.Cars.Count; k--)
                                            {
                                                train.Cars.Add(new TrailerCar());
                                                train.Couplers.Add(new Coupler());

                                                train.ApplyPowerNotchesToCar();
                                                train.ApplyBrakeNotchesToCar();
                                                train.ApplyLocoBrakeNotchesToCar();
                                            }

                                            if (string.IsNullOrEmpty(b))
                                            {
                                                Interface.AddMessage(MessageType.Error, true, $"An empty car object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                            else if (Path.ContainsInvalidChars(b))
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                            else
                                            {
                                                string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                if (!File.Exists(file))
                                                {
                                                    Interface.AddMessage(MessageType.Warning, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                }

                                                train.Cars[n].Object = file;
                                            }
                                        }
                                        else
                                        {
                                            Interface.AddMessage(MessageType.Error, false, $"The car index {n} does not reference an existing car at line {(i + 1).ToString(culture)} in file {fileName}");
                                        }
                                    }
                                    else
                                    {
                                        Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                                    }
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }

                            i++;
                        }

                        i--;
                        break;

                    default:
                        if (lines[i].StartsWith("[car", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // car
                            string t = lines[i].Substring(4, lines[i].Length - 5);
                            int    n;

                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    for (int j = n; j >= train.Cars.Count; j--)
                                    {
                                        train.Cars.Add(new TrailerCar());
                                        train.Couplers.Add(new Coupler());

                                        train.ApplyPowerNotchesToCar();
                                        train.ApplyBrakeNotchesToCar();
                                        train.ApplyLocoBrakeNotchesToCar();
                                    }

                                    i++;

                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Any())
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                            if (j >= 0)
                                            {
                                                string a = lines[i].Substring(0, j).TrimEnd();
                                                string b = lines[i].Substring(j + 1).TrimStart();

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty car object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                        if (!File.Exists(file))
                                                        {
                                                            Interface.AddMessage(MessageType.Warning, true, $"The car object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }

                                                        train.Cars[n].Object = file;
                                                    }
                                                    break;

                                                case "length":
                                                {
                                                    double m;

                                                    if (double.TryParse(b, NumberStyles.Float, culture, out m))
                                                    {
                                                        if (m > 0.0)
                                                        {
                                                            train.Cars[n].Length = m;
                                                        }
                                                        else
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"Value is expected to be a positive floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                }
                                                break;

                                                case "axles":
                                                    int k = b.IndexOf(',');

                                                    if (k >= 0)
                                                    {
                                                        string c = b.Substring(0, k).TrimEnd();
                                                        string d = b.Substring(k + 1).TrimStart();
                                                        double rear, front;

                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out rear))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out front))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Front is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (rear >= front)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be less than Front in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else
                                                        {
                                                            train.Cars[n].RearAxle     = rear;
                                                            train.Cars[n].FrontAxle    = front;
                                                            train.Cars[n].DefinedAxles = true;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    break;

                                                case "reversed":
                                                    train.Cars[n].Reversed = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                case "loadingsway":
                                                    train.Cars[n].LoadingSway = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    break;
                                                }
                                            }
                                        }

                                        i++;
                                    }

                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The car index {t} does not reference an existing car at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The car index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                        }
                        else if (lines[i].StartsWith("[coupler", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // coupler
                            string t = lines[i].Substring(8, lines[i].Length - 9);
                            int    n;

                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                if (n >= 0)
                                {
                                    for (int j = n; j >= train.Couplers.Count; j--)
                                    {
                                        train.Cars.Add(new TrailerCar());
                                        train.Couplers.Add(new Coupler());

                                        train.ApplyPowerNotchesToCar();
                                        train.ApplyBrakeNotchesToCar();
                                        train.ApplyLocoBrakeNotchesToCar();
                                    }

                                    i++;

                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Any())
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                            if (j >= 0)
                                            {
                                                string a = lines[i].Substring(0, j).TrimEnd();
                                                string b = lines[i].Substring(j + 1).TrimStart();

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "distances":
                                                {
                                                    int k = b.IndexOf(',');

                                                    if (k >= 0)
                                                    {
                                                        string c = b.Substring(0, k).TrimEnd();
                                                        string d = b.Substring(k + 1).TrimStart();
                                                        double min, max;

                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out min))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out max))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Maximum is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (min > max)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Minimum is expected to be less than Maximum in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else
                                                        {
                                                            train.Couplers[n].Min = min;
                                                            train.Couplers[n].Max = max;
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                }
                                                break;

                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty coupler object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                        if (!File.Exists(file))
                                                        {
                                                            Interface.AddMessage(MessageType.Warning, true, $"The coupler object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }

                                                        train.Couplers[n].Object = file;
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                        }

                                        i++;
                                    }

                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The coupler index {t} does not reference an existing coupler at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The coupler index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                        }
                        else if (lines[i].StartsWith("[bogie", StringComparison.OrdinalIgnoreCase) & lines[i].EndsWith("]", StringComparison.Ordinal))
                        {
                            // bogie
                            string t = lines[i].Substring(6, lines[i].Length - 7);
                            int    n;

                            if (int.TryParse(t, NumberStyles.Integer, culture, out n))
                            {
                                //Assuming that there are two bogies per car
                                bool IsOdd    = (n % 2 != 0);
                                int  CarIndex = n / 2;

                                if (n >= 0)
                                {
                                    for (int j = CarIndex; j >= train.Cars.Count; j--)
                                    {
                                        train.Cars.Add(new TrailerCar());
                                        train.Couplers.Add(new Coupler());

                                        train.ApplyPowerNotchesToCar();
                                        train.ApplyBrakeNotchesToCar();
                                        train.ApplyLocoBrakeNotchesToCar();
                                    }

                                    i++;

                                    while (i < lines.Length && !lines[i].StartsWith("[", StringComparison.Ordinal) & !lines[i].EndsWith("]", StringComparison.Ordinal))
                                    {
                                        if (lines[i].Any())
                                        {
                                            int j = lines[i].IndexOf("=", StringComparison.Ordinal);

                                            if (j >= 0)
                                            {
                                                string a = lines[i].Substring(0, j).TrimEnd();
                                                string b = lines[i].Substring(j + 1).TrimStart();

                                                switch (a.ToLowerInvariant())
                                                {
                                                case "object":
                                                    if (string.IsNullOrEmpty(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, true, $"An empty bogie object was supplied at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else if (Path.ContainsInvalidChars(b))
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"File contains illegal characters at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    else
                                                    {
                                                        string file = Path.CombineFile(System.IO.Path.GetDirectoryName(fileName), b);

                                                        if (!File.Exists(file))
                                                        {
                                                            Interface.AddMessage(MessageType.Warning, true, $"The bogie object {file} does not exist at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }

                                                        if (IsOdd)
                                                        {
                                                            train.Cars[CarIndex].RearBogie.Object = b;
                                                        }
                                                        else
                                                        {
                                                            train.Cars[CarIndex].FrontBogie.Object = b;
                                                        }
                                                    }
                                                    break;

                                                case "axles":
                                                    int k = b.IndexOf(',');

                                                    if (k >= 0)
                                                    {
                                                        string c = b.Substring(0, k).TrimEnd();
                                                        string d = b.Substring(k + 1).TrimStart();
                                                        double rear, front;

                                                        if (!double.TryParse(c, NumberStyles.Float, culture, out rear))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (!double.TryParse(d, NumberStyles.Float, culture, out front))
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Front is expected to be a floating-point number in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else if (rear >= front)
                                                        {
                                                            Interface.AddMessage(MessageType.Error, false, $"Rear is expected to be less than Front in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                        }
                                                        else
                                                        {
                                                            if (IsOdd)
                                                            {
                                                                train.Cars[CarIndex].RearBogie.RearAxle     = rear;
                                                                train.Cars[CarIndex].RearBogie.FrontAxle    = front;
                                                                train.Cars[CarIndex].RearBogie.DefinedAxles = true;
                                                            }
                                                            else
                                                            {
                                                                train.Cars[CarIndex].FrontBogie.RearAxle     = rear;
                                                                train.Cars[CarIndex].FrontBogie.FrontAxle    = front;
                                                                train.Cars[CarIndex].FrontBogie.DefinedAxles = true;
                                                            }
                                                        }
                                                    }
                                                    else
                                                    {
                                                        Interface.AddMessage(MessageType.Error, false, $"An argument-separating comma is expected in {a} at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    }
                                                    break;

                                                case "reversed":
                                                    if (IsOdd)
                                                    {
                                                        train.Cars[CarIndex].FrontBogie.Reversed = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    }
                                                    else
                                                    {
                                                        train.Cars[CarIndex].RearBogie.Reversed = b.Equals("true", StringComparison.OrdinalIgnoreCase);
                                                    }
                                                    break;

                                                default:
                                                    Interface.AddMessage(MessageType.Warning, false, $"Unsupported key-value pair {a} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                                    break;
                                                }
                                            }
                                            else
                                            {
                                                Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                                            }
                                        }

                                        i++;
                                    }

                                    i--;
                                }
                                else
                                {
                                    Interface.AddMessage(MessageType.Error, false, $"The bogie index {t} does not reference an existing car at line {(i + 1).ToString(culture)} in file {fileName}");
                                }
                            }
                            else
                            {
                                Interface.AddMessage(MessageType.Error, false, $"The bogie index is expected to be an integer at line {(i + 1).ToString(culture)} in file {fileName}");
                            }
                        }
                        else
                        {
                            Interface.AddMessage(MessageType.Error, false, $"Invalid statement {lines[i]} encountered at line {(i + 1).ToString(culture)} in file {fileName}");
                        }
                        break;
                    }
                }
            }
        }