/// <summary>
        /// Creates an array of midway points from a byte array.
        /// </summary>
        /// <remarks>Remember that the first six bytes should be <see cref="MmpHeader"/> and the version numbers (major, minor, bugfix)</remarks>
        /// <param name="data">The binary data which contains the midway points.</param>
        /// <param name="major_">The major version (for backwards compatibility).</param>
        /// <param name="minor_">The minor version (for backwards compatibility).</param>
        /// <param name="bugfix_">The bugfix version (for backwards compatibility).</param>
        /// <returns>A [<see cref="maxLevels"/>, <see cref="maxMidways"/>] array of midway points.</returns>
        public static Midway[,] FromBinary(byte[] data, byte major_ = MajorVersion, byte minor_ = MinorVersion, byte bugfix_ = BugfixVersion)
        {
            int iData = 0;

            Midway[,] midways = new Midway[maxLevels, maxMidways];
            byte[] header = new byte[3];
            int    major, minor, bugfix; // Placeholder

            // Header stuff
            Array.Copy(data, iData, header, 0, 3);
            if (Encoding.ASCII.GetString(header) != MmpHeader)
            {
                throw new ArgumentException("This file is not a proper .mmp file.");
            }
            major  = data[3]; //
            minor  = data[4]; // Store version number to local variables.
            bugfix = data[5]; //

            iData += 6;       // Increment byte index.

            // Loop starts here.
            for (int i = 0; i < maxLevels; i++)
            {
                for (int j = 0; j < maxMidways; j++)
                {
                    // For each midway point, get four bytes
                    midways[i, j].ConvertFromBytes(data.SubArray(iData, 4));
                    iData += 4;
                }
            }
            return(midways);
        }
        /// <summary>
        /// Removes any unused Midway point (<see cref="IsEmpty"/> for the definition details.).
        /// </summary>
        /// <param name="midwayTable">The table which should be compressed.</param>
        public static void CompressTable(ref Midway[,] midwayTable)
        {
            // Create a new, empty table
            Midway[,] newTable = new Midway[maxLevels, maxMidways];

            // For each level...
            for (int j = 0; j < maxLevels; j++)
            {
                // Index for the new table
                int iNew = 0;

                for (int iOld = 0; iOld < maxMidways; iOld++)
                {
                    // Only copy the old midway point value
                    if (!midwayTable[j, iOld].IsEmpty())
                    {
                        newTable[j, iNew++] = midwayTable[j, iOld];
                    }
                }
            }

            midwayTable = newTable;
        }
        /// <summary>
        /// Opens multi_midway_tables.asm and generates an array of midway points.
        /// </summary>
        /// <returns>The 2D midway point table from the ASM file.</returns>
        public static Midway[,] ImportAsm(Stream stream)
        {
            // Generate a maxLevels * maxMidways Midway array.
            Midway[,] midways = new Midway[maxLevels, maxMidways];
            try
            {
                using (StreamReader reader = new StreamReader(stream))
                {
                    // The difficult part is to read the arrays.
                    // Remember there is a variable amount of lines in table.
                    // The trick is to only read lines which have got a '$' in it
                    // In order to verify the file, it needs to have the following conditions:
                    // - There are 96 different rows with data for 96 levels
                    // - Each table is a 16-bit table.
                    // Failing any of the conditions means: It's not a valid file.
                    // There is no checks for the length.
                    int    iLevel = 0;
                    bool   containsData;
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        containsData = false;

                        int iStart       = 0;
                        int iMidway      = 0;
                        int commentIndex = line.IndexOf(';');

                        // Ignore comments
                        if (commentIndex >= 0)
                        {
                            line = line.Substring(0, commentIndex);
                        }
                        // Remove leading spaces and tabs to prevent confusions.
                        char[] charsToTrim = { ' ', '\t' };
                        line = line.Trim(charsToTrim);

                        if (line.Length < 3)
                        {
                            continue;                   // This includes lines which are less than 3 chars long.
                        }
                        if (line.Substring(0, 3) != "dw ")
                        {
                            continue;                                // Now check if the line starts with a "dw " (start of a table).
                        }
                        // Let's go!
                        while ((iStart = line.IndexOf('$', iStart)) >= 0)
                        {
                            try
                            {
                                midways[iLevel, iMidway].CalculateMidway(line.Substring(++iStart, 4));
                                containsData = true;
                            }
                            catch (ArgumentException ex)
                            {
                                throw new ArgumentException(ex.Message);
                            }

                            // Increment the index to get the next midway point, increment the starting index.
                            iMidway++;
                            iStart++;
                        }
                        if (containsData)
                        {
                            if (++iLevel > 96)
                            {
                                throw new ArgumentOutOfRangeException("Error: Multi_midway_tables.asm isn't a valid file.");
                            }
                        }
                    }
                    // Before we return, we have to make sure there have been enough levels to read.
                    if (iLevel != 96)
                    {
                        throw new ArgumentOutOfRangeException("Error: Multi_midway_tables.asm isn't a valid file.");
                    }
                }
            }
            catch (IOException ex)
            {
                throw new IOException("Error: Multi_midway_tables.asm couldn't be read: " + ex.Message);
            }
            return(midways);
        }