Exemplo n.º 1
0
        public void TestRemaining()
        {
            var match     = new SingleChar('a');
            var remaining = match
                            .Yield()
                            .Remaining();

            Assert.AreEqual(char.MaxValue, remaining.Count);
        }
Exemplo n.º 2
0
        void UpdateOutput(Painter painter)
        {
            string oneChar = SingleChar.Trim();

            if (string.IsNullOrEmpty(oneChar))
            {
                return;
            }
            //
            char selectedChar = oneChar[0];

            DrawOutput(painter, _typeface, selectedChar);
        }
Exemplo n.º 3
0
        private bool LoadVersion5(GR.Memory.ByteBuffer Data)
        {
            BackgroundColor = Data.ByteAt(4);
            MultiColor1     = Data.ByteAt(5);
            MultiColor2     = Data.ByteAt(6);
            CustomColor     = Data.ByteAt(7);
            TileColorMode   = (ColorMode)Data.ByteAt(8);

            byte flags   = Data.ByteAt(9);
            bool noTiles = ((flags & 0x01) == 0);

            MultiColor = ((flags & 0x04) != 0);
            bool isExpanded = ((flags & 0x02) != 0);

            NumChars   = Data.UInt16At(10) + 1;
            NumTiles   = Data.UInt16At(12) + 1;
            TileWidth  = Data.ByteAt(14);
            TileHeight = Data.ByteAt(15);

            MapWidth  = Data.UInt16At(16);
            MapHeight = Data.UInt16At(18);

            if (noTiles)
            {
                // fake tiles
                TileWidth  = 1;
                TileHeight = 1;
                NumTiles   = 256;
            }


            int headerSize          = 20;
            int offsetToCharData    = headerSize;
            int offsetToCharAttribs = offsetToCharData + NumChars * 8;
            int offsetToTileData    = offsetToCharAttribs + NumChars;
            int offsetToTileColors  = offsetToTileData + NumTiles * TileWidth * TileHeight * 2;

            if ((isExpanded) ||
                (noTiles))
            {
                offsetToTileColors = offsetToTileData;
            }
            int offsetToMapData = offsetToTileColors + NumTiles;

            if ((TileColorMode != ColorMode.PER_TILE) ||
                (noTiles))
            {
                offsetToMapData = offsetToTileColors;
            }

            // char_data/char_attribs
            for (int charIndex = 0; charIndex < NumChars; ++charIndex)
            {
                SingleChar newChar = new SingleChar();
                newChar.Data = Data.SubBuffer(offsetToCharData + charIndex * 8, 8);
                if (TileColorMode == ColorMode.PER_TILE_CELL)
                {
                    newChar.Color = Data.ByteAt(offsetToCharAttribs + charIndex) & 0x0f;
                }
                else
                {
                    newChar.Color = CustomColor;
                }

                Characters.Add(newChar);
            }

            // tile_data
            if (noTiles)
            {
                for (int i = 0; i < NumTiles; ++i)
                {
                    Tile tile = new Tile();

                    tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                    tile.CharData.SetU16At(0, (ushort)i);

                    tile.ColorData.Resize((uint)(TileWidth * TileHeight));
                    tile.ColorData.SetU8At(0, (byte)CustomColor);

                    Tiles.Add(tile);
                }
                if (NumChars < 256)
                {
                    // add all chars for safety reasons
                    for (int i = NumChars; i < 256; ++i)
                    {
                        SingleChar newChar = new SingleChar();
                        newChar.Data = new GR.Memory.ByteBuffer(8);
                        if (TileColorMode == ColorMode.PER_TILE_CELL)
                        {
                            newChar.Color = Data.ByteAt(offsetToCharAttribs + i) & 0x0f;
                        }
                        else
                        {
                            newChar.Color = CustomColor;
                        }

                        Characters.Add(newChar);
                    }
                }
            }
            else
            {
                for (int i = 0; i < NumTiles; ++i)
                {
                    Tile tile = new Tile();

                    tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                    tile.ColorData.Resize((uint)(TileWidth * TileHeight));

                    Tiles.Add(tile);
                }

                if (isExpanded)
                {
                    byte curCharIndex = 0;
                    for (int i = 0; i < NumTiles; ++i)
                    {
                        for (int j = 0; j < TileWidth * TileHeight; ++j)
                        {
                            Tiles[i].CharData.SetU16At(j * 2, curCharIndex);
                            ++curCharIndex;
                        }
                    }
                }
                else
                {
                    // tile_data.      Size = NUM_TILES * TILE_WIDTH * TILE_HEIGHT bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded")
                    for (int i = 0; i < NumTiles; ++i)
                    {
                        for (int j = 0; j < TileWidth * TileHeight; ++j)
                        {
                            Tiles[i].CharData.SetU16At(j * 2, Data.UInt16At(offsetToTileData + i * TileWidth * TileHeight * 2 + j * 2));
                        }
                    }
                }
            }

            // TILE_COLOURS.   Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile)
            if (TileColorMode == ColorMode.PER_TILE)
            {
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int y = 0; y < TileHeight; ++y)
                    {
                        for (int x = 0; x < TileWidth; ++x)
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetToTileColors + i) & 0x0f));
                        }
                    }
                }
            }
            else if (TileColorMode == ColorMode.PER_TILE_CELL)
            {
                // with V5 this actually means per character
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int y = 0; y < TileHeight; ++y)
                    {
                        for (int x = 0; x < TileWidth; ++x)
                        {
                            byte charColor = (byte)Characters[Tiles[i].CharData.ByteAt(2 * (x + y * TileWidth))].Color;
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, charColor);
                        }
                    }
                }
            }
            else if (TileColorMode == ColorMode.GLOBAL)
            {
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int y = 0; y < TileHeight; ++y)
                    {
                        for (int x = 0; x < TileWidth; ++x)
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)CustomColor);
                        }
                    }
                }
            }

            /*
             * else if ( TileColorMode == ColorMode.PER_TILE_CELL )
             * {
             * for ( int i = 0; i < NumTiles; ++i )
             * {
             *  for ( int y = 0; y < TileHeight; ++y )
             *  {
             *    for ( int x = 0; x < TileWidth; ++x )
             *    {
             *      Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight ) & 0x0f ) );
             *    }
             *  }
             * }
             * }*/

            // MAP_DATA.        Size =  MAP_WID x MAP_HEI bytes.
            // tile indices are now 16 bit! for now force 8bit

            //MapData = Data.SubBuffer( offsetMapData, MapWidth * MapHeight * 2 );

            MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight));

            for (int i = 0; i < MapHeight; ++i)
            {
                for (int j = 0; j < MapWidth; ++j)
                {
                    MapData.SetU8At(i * MapWidth + j, Data.ByteAt(offsetToMapData + 2 * (i * MapWidth + j)));
                }
            }
            return(true);
        }
Exemplo n.º 4
0
        private bool LoadVersion4(GR.Memory.ByteBuffer Data)
        {
            BackgroundColor = Data.ByteAt(4);
            MultiColor1     = Data.ByteAt(5);
            MultiColor2     = Data.ByteAt(6);
            CustomColor     = Data.ByteAt(7);
            TileColorMode   = (ColorMode)Data.ByteAt(8);
            MultiColor      = (Data.ByteAt(9) != 0);

            NumChars   = Data.UInt16At(10) + 1;
            NumTiles   = Data.ByteAt(12) + 1;
            TileWidth  = Data.ByteAt(13);
            TileHeight = Data.ByteAt(14);

            MapWidth  = Data.UInt16At(15);
            MapHeight = Data.UInt16At(17);

            bool isExpanded = (Data.ByteAt(19) != 0);

            int offsetToCharAttribs = 24 + NumChars * 8;

            for (int charIndex = 0; charIndex < NumChars; ++charIndex)
            {
                SingleChar newChar = new SingleChar();
                newChar.Data  = Data.SubBuffer(24 + charIndex * 8, 8);
                newChar.Color = Data.ByteAt(offsetToCharAttribs + charIndex) & 0x0f;

                Characters.Add(newChar);
            }

            for (int i = 0; i < NumTiles; ++i)
            {
                Tile tile = new Tile();

                tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                tile.ColorData.Resize((uint)(TileWidth * TileHeight));

                Tiles.Add(tile);
            }

            if (isExpanded)
            {
                byte curCharIndex = 0;
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int j = 0; j < TileWidth * TileHeight; ++j)
                    {
                        Tiles[i].CharData.SetU16At(j * 2, curCharIndex);
                        ++curCharIndex;
                    }
                }
            }
            else
            {
                // CELL_DATA.      Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded")
                int offsetCellData = 24 + NumChars * 8 + NumChars;
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int j = 0; j < TileWidth * TileHeight; ++j)
                    {
                        Tiles[i].CharData.SetU16At(j * 2, Data.UInt16At(offsetCellData + i * TileWidth * TileHeight * 2 + j * 2));
                    }
                }
            }
            // CELL_ATTRIBS.   Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes (exists for ALL modes)

            int offsetCellAttribs = 24 + NumChars * 8 + NumChars;

            if (!isExpanded)
            {
                offsetCellAttribs += NumTiles * TileWidth * TileHeight * 2;
            }
            for (int i = 0; i < NumTiles; ++i)
            {
                for (int y = 0; y < TileHeight; ++y)
                {
                    for (int x = 0; x < TileWidth; ++x)
                    {
                        if (TileColorMode == ColorMode.PER_TILE_CELL)
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight) & 0x0f));
                        }
                        else
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)CustomColor);
                        }
                    }
                }
            }

            // TILE_ATTRIBS.   Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile)
            int offsetTileAttribs = offsetCellAttribs + NumTiles * TileWidth * TileHeight;

            if (TileColorMode == ColorMode.PER_TILE)
            {
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int y = 0; y < TileHeight; ++y)
                    {
                        for (int x = 0; x < TileWidth; ++x)
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetTileAttribs + i) & 0x0f));
                        }
                    }
                }
            }

            /*
             * if ( TileColorMode == ColorMode.PER_TILE_CELL )
             * {
             * for ( int i = 0; i < NumTiles; ++i )
             * {
             *  for ( int y = 0; y < TileHeight; ++y )
             *  {
             *    for ( int x = 0; x < TileWidth; ++x )
             *    {
             *      Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight ) & 0x0f ) );
             *    }
             *  }
             * }
             * }*/

            // MAP_DATA.        Size =  MAP_WID x MAP_HEI bytes.
            int offsetMapData = offsetTileAttribs;

            if (TileColorMode == ColorMode.PER_TILE)
            {
                offsetMapData += NumTiles;
            }

            MapData = Data.SubBuffer(offsetMapData, MapWidth * MapHeight);
            return(true);
        }
Exemplo n.º 5
0
 public override bool Create(CharacterClassBuilder builder,
                             out IMatch?match)
 {
     match = new SingleChar(ch);
     return(true);
 }
Exemplo n.º 6
0
        private bool LoadVersion7(GR.Memory.ByteBuffer Data)
        {
            BackgroundColor  = Data.ByteAt(4);
            MultiColor1      = Data.ByteAt(5);
            MultiColor2      = Data.ByteAt(6);
            BackgroundColor4 = Data.ByteAt(7);
            CustomColor      = Data.ByteAt(8);
            TileColorMode    = (ColorMode)Data.ByteAt(9);

            CharsetMode = (Types.CharsetMode)Data.ByteAt(10);

            byte flags          = Data.ByteAt(11);
            bool tileSysEnabled = ((flags & 0x01) != 0);


            ushort charDataBlockID      = 0xdab0;
            ushort charAttributeBlockID = 0xdab1;
            ushort mapDataBlockID       = 0xdab2;


            if (!tileSysEnabled)
            {
                // fake tiles (one per char)
                TileWidth  = 1;
                TileHeight = 1;
                NumTiles   = 256;

                for (int i = 0; i < NumTiles; ++i)
                {
                    Tile tile = new Tile();

                    tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                    tile.CharData.SetU16At(0, (ushort)i);

                    tile.ColorData.Resize((uint)(TileWidth * TileHeight));
                    tile.ColorData.SetU8At(0, (byte)CustomColor);

                    Tiles.Add(tile);
                }
            }

            var reader = Data.MemoryReader();

            reader.Skip(12);

            while (reader.DataAvailable)
            {
                ushort blockID = reader.ReadUInt16NetworkOrder();

                if (blockID == mapDataBlockID)
                {
                    if (tileSysEnabled)
                    {
                        // Tile data block

                        // TILECNT: Tile count minus one(16 - bit, LSBF).
                        NumTiles = reader.ReadUInt16() + 1;

                        // TILEWID: Tile width( byte).
                        TileWidth = reader.ReadUInt8();
                        // TILEHEI: Tile height( byte).
                        TileHeight = reader.ReadUInt8();

                        // TILEDAT: Tile data, 16 bits per tile cell( LSBF) for TILEWID* TILEHEI cells * TILECNT items, cells are in LRTB order.
                        for (int i = 0; i < NumTiles; ++i)
                        {
                            Tile tile = new Tile();

                            tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                            tile.ColorData.Resize((uint)(TileWidth * TileHeight));

                            Tiles.Add(tile);
                        }
                        if (NumChars < 256)
                        {
                            // add all chars for safety reasons
                            for (int i = NumChars; i < 256; ++i)
                            {
                                SingleChar newChar = new SingleChar();
                                newChar.Data = new GR.Memory.ByteBuffer(8);
                                Characters.Add(newChar);
                            }
                        }
                        for (int i = 0; i < NumTiles; ++i)
                        {
                            for (int j = 0; j < TileWidth * TileHeight; ++j)
                            {
                                Tiles[i].CharData.SetU16At(j * 2, reader.ReadUInt16());
                            }
                        }
                    }
                    else
                    {
                        // BLKMARK : Block marker (0xDA, 0xBn).
                        // MAPWID: Map Width(16 - bit, LSBF).
                        // MAPHEI: Map height(16 - bit, LSBF).
                        // MAPDAT: Map data, 16 bits per cell( LSBF ) for MAPWID* MAPHEI cells, cells are in LRTB order.
                        MapWidth  = reader.ReadUInt16();
                        MapHeight = reader.ReadUInt16();

                        MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight));

                        for (int i = 0; i < MapHeight; ++i)
                        {
                            for (int j = 0; j < MapWidth; ++j)
                            {
                                MapData.SetU8At(i * MapWidth + j, (byte)reader.ReadUInt16());
                            }
                        }
                    }
                }

                if (blockID == charDataBlockID)
                {
                    // Character data block

                    // CHARCNT: Character image count minus one( 16 - bit, LSBF ).
                    NumChars = reader.ReadUInt16() + 1;

                    // CHARDAT : Character image data( eight bytes / rows per image for CHARCNT images, rows are in TB order ).
                    for (int charIndex = 0; charIndex < NumChars; ++charIndex)
                    {
                        SingleChar newChar = new SingleChar();
                        newChar.Data  = new GR.Memory.ByteBuffer();
                        newChar.Color = CustomColor;
                        reader.ReadBlock(newChar.Data, 8);
                        Characters.Add(newChar);
                    }

                    if (!tileSysEnabled)
                    {
                        if (NumChars < 256)
                        {
                            // add all chars for safety reasons
                            for (int i = NumChars; i < 256; ++i)
                            {
                                SingleChar newChar = new SingleChar();
                                newChar.Data  = new GR.Memory.ByteBuffer(8);
                                newChar.Color = CustomColor;

                                Characters.Add(newChar);
                            }
                        }
                    }
                }
                else if (blockID == charAttributeBlockID)
                {
                    // char attributes
                    // BLKMARK: Block marker(0xDA, 0xB1).
                    // CHARATTS: Char attribute data, one byte per char image for CHARCNT images, low nybble = colour, high nybble = material.
                    //           nb.colours are only stored when the colouring mode is "per character".
                    for (int charIndex = 0; charIndex < NumChars; ++charIndex)
                    {
                        if (TileColorMode == ColorMode.PER_TILE_CELL)
                        {
                            Characters[charIndex].Color = reader.ReadUInt8() & 0x0f;
                            if (!tileSysEnabled)
                            {
                                Tiles[charIndex].ColorData.SetU8At(0, (byte)Characters[charIndex].Color);
                            }
                        }
                    }
                }
            }


            /*
             *
             *
             * int headerSize = 20;
             * int offsetToCharData = headerSize;
             * int offsetToCharAttribs = offsetToCharData + NumChars * 8;
             * int offsetToTileData = offsetToCharAttribs + NumChars;
             * int offsetToTileColors = offsetToTileData + NumTiles * TileWidth * TileHeight * 2;
             * if ( ( tileSysEnabled )
             || ( noTiles ) )
             ||{
             ||offsetToTileColors = offsetToTileData;
             ||}
             ||int offsetToMapData = offsetToTileColors + NumTiles;
             ||if ( ( TileColorMode != ColorMode.PER_TILE )
             || ( noTiles ) )
             ||{
             ||offsetToMapData = offsetToTileColors;
             ||}
             ||
             ||// tile_data
             ||if ( noTiles )
             ||{
             ||for ( int i = 0; i < NumTiles; ++i )
             ||{
             || Tile tile = new Tile();
             ||
             || tile.CharData.Resize( (uint)( TileWidth * TileHeight * 2 ) );
             || tile.CharData.SetU16At( 0, (ushort)i );
             ||
             || tile.ColorData.Resize( (uint)( TileWidth * TileHeight ) );
             || tile.ColorData.SetU8At( 0, (byte)CustomColor );
             ||
             || Tiles.Add( tile );
             ||}
             ||if ( NumChars < 256 )
             ||{
             || // add all chars for safety reasons
             || for ( int i = NumChars; i < 256; ++i )
             || {
             ||   SingleChar    newChar = new SingleChar();
             ||   newChar.Data = new GR.Memory.ByteBuffer( 8 );
             ||   if ( TileColorMode == ColorMode.PER_TILE_CELL )
             ||   {
             ||     newChar.Color = Data.ByteAt( offsetToCharAttribs + i ) & 0x0f;
             ||   }
             ||   else
             ||   {
             ||     newChar.Color = CustomColor;
             ||   }
             ||
             ||   Characters.Add( newChar );
             || }
             ||}
             ||}
             ||else
             ||{
             ||for ( int i = 0; i < NumTiles; ++i )
             ||{
             || Tile tile = new Tile();
             ||
             || tile.CharData.Resize( (uint)( TileWidth * TileHeight * 2 ) );
             || tile.ColorData.Resize( (uint)( TileWidth * TileHeight ) );
             ||
             || Tiles.Add( tile );
             ||}
             ||
             ||if ( tileSysEnabled )
             ||{
             || byte curCharIndex = 0;
             || for ( int i = 0; i < NumTiles; ++i )
             || {
             ||   for ( int j = 0; j < TileWidth * TileHeight; ++j )
             ||   {
             ||     Tiles[i].CharData.SetU16At( j * 2, curCharIndex );
             ++curCharIndex;
             ||   }
             || }
             ||}
             ||else
             ||{
             || // tile_data.      Size = NUM_TILES * TILE_WIDTH * TILE_HEIGHT bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded")
             || for ( int i = 0; i < NumTiles; ++i )
             || {
             ||   for ( int j = 0; j < TileWidth * TileHeight; ++j )
             ||   {
             ||     Tiles[i].CharData.SetU16At( j * 2, Data.UInt16At( offsetToTileData + i * TileWidth * TileHeight * 2 + j * 2 ) );
             ||   }
             || }
             ||}
             ||}
             ||
             ||// TILE_COLOURS.   Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile)
             ||if ( TileColorMode == ColorMode.PER_TILE )
             ||{
             ||for ( int i = 0; i < NumTiles; ++i )
             ||{
             || for ( int y = 0; y < TileHeight; ++y )
             || {
             ||   for ( int x = 0; x < TileWidth; ++x )
             ||   {
             ||     Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetToTileColors + i ) & 0x0f ) );
             ||   }
             || }
             ||}
             ||}
             ||else if ( TileColorMode == ColorMode.PER_TILE_CELL )
             ||{
             ||// with V5 this actually means per character
             ||for ( int i = 0; i < NumTiles; ++i )
             ||{
             || for ( int y = 0; y < TileHeight; ++y )
             || {
             ||   for ( int x = 0; x < TileWidth; ++x )
             ||   {
             ||     byte    charColor = (byte)Characters[Tiles[i].CharData.ByteAt( 2 * ( x + y * TileWidth ) )].Color;
             ||     Tiles[i].ColorData.SetU8At( x + y * TileWidth, charColor );
             ||   }
             || }
             ||}
             ||}
             ||else if ( TileColorMode == ColorMode.GLOBAL )
             ||{
             ||for ( int i = 0; i < NumTiles; ++i )
             ||{
             || for ( int y = 0; y < TileHeight; ++y )
             || {
             ||   for ( int x = 0; x < TileWidth; ++x )
             ||   {
             ||     Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)CustomColor );
             ||   }
             || }
             ||}
             ||}
             ||else if ( TileColorMode == ColorMode.PER_TILE_CELL )
             ||{
             ||for ( int i = 0; i < NumTiles; ++i )
             ||{
             || for ( int y = 0; y < TileHeight; ++y )
             || {
             ||   for ( int x = 0; x < TileWidth; ++x )
             ||   {
             ||     Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight ) & 0x0f ) );
             ||   }
             || }
             ||}
             ||}
             ||
             */
            return(true);
        }
Exemplo n.º 7
0
        public bool LoadFromFile(GR.Memory.ByteBuffer Data)
        {
            Characters.Clear();
            MapData.Clear();

            if ((Data == null) ||
                (Data.Length < 24) ||
                (Data.ByteAt(0) != 'C') ||
                (Data.ByteAt(1) != 'T') ||
                (Data.ByteAt(2) != 'M'))
            {
                // not a valid CTM file
                return(false);
            }
            int version = Data.ByteAt(3);

            if (version != 4)
            {
                System.Windows.Forms.MessageBox.Show("Currently only version 4 of Charpad project files is supported. Sorry!", "Unsupported version " + version);
                return(false);
            }

            BackgroundColor = Data.ByteAt(4);
            MultiColor1     = Data.ByteAt(5);
            MultiColor2     = Data.ByteAt(6);
            CustomColor     = Data.ByteAt(7);
            TileColorMode   = (ColorMode)Data.ByteAt(8);
            MultiColor      = (Data.ByteAt(9) != 0);

            NumChars   = Data.UInt16At(10) + 1;
            NumTiles   = Data.ByteAt(12) + 1;
            TileWidth  = Data.ByteAt(13);
            TileHeight = Data.ByteAt(14);

            MapWidth  = Data.UInt16At(15);
            MapHeight = Data.UInt16At(17);

            bool isExpanded = (Data.ByteAt(19) != 0);

            int offsetToCharAttribs = 24 + NumChars * 8;

            for (int charIndex = 0; charIndex < NumChars; ++charIndex)
            {
                SingleChar newChar = new SingleChar();
                newChar.Data  = Data.SubBuffer(24 + charIndex * 8, 8);
                newChar.Color = Data.ByteAt(offsetToCharAttribs + charIndex) & 0x0f;

                Characters.Add(newChar);
            }

            for (int i = 0; i < NumTiles; ++i)
            {
                Tile tile = new Tile();

                tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                tile.ColorData.Resize((uint)(TileWidth * TileHeight));

                Tiles.Add(tile);
            }

            if (isExpanded)
            {
                byte curCharIndex = 0;
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int j = 0; j < TileWidth * TileHeight; ++j)
                    {
                        Tiles[i].CharData.SetU16At(j * 2, curCharIndex);
                        ++curCharIndex;
                    }
                }
            }
            else
            {
                // CELL_DATA.      Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded")
                int offsetCellData = 24 + NumChars * 8 + NumChars;
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int j = 0; j < TileWidth * TileHeight; ++j)
                    {
                        Tiles[i].CharData.SetU16At(j * 2, Data.UInt16At(offsetCellData + i * TileWidth * TileHeight * 2 + j * 2));
                    }
                }
            }
            // CELL_ATTRIBS.   Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes (exists for ALL modes)

            int offsetCellAttribs = 24 + NumChars * 8 + NumChars;

            if (!isExpanded)
            {
                offsetCellAttribs += NumTiles * TileWidth * TileHeight * 2;
            }
            for (int i = 0; i < NumTiles; ++i)
            {
                for (int y = 0; y < TileHeight; ++y)
                {
                    for (int x = 0; x < TileWidth; ++x)
                    {
                        if (TileColorMode == ColorMode.PER_TILE_CELL)
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight) & 0x0f));
                        }
                        else
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)CustomColor);
                        }
                    }
                }
            }

            // TILE_ATTRIBS.   Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile)
            int offsetTileAttribs = offsetCellAttribs + NumTiles * TileWidth * TileHeight;

            if (TileColorMode == ColorMode.PER_TILE)
            {
                for (int i = 0; i < NumTiles; ++i)
                {
                    for (int y = 0; y < TileHeight; ++y)
                    {
                        for (int x = 0; x < TileWidth; ++x)
                        {
                            Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetTileAttribs + i) & 0x0f));
                        }
                    }
                }
            }

            /*
             * if ( TileColorMode == ColorMode.PER_TILE_CELL )
             * {
             * for ( int i = 0; i < NumTiles; ++i )
             * {
             *  for ( int y = 0; y < TileHeight; ++y )
             *  {
             *    for ( int x = 0; x < TileWidth; ++x )
             *    {
             *      Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight ) & 0x0f ) );
             *    }
             *  }
             * }
             * }*/

            // MAP_DATA.        Size =  MAP_WID x MAP_HEI bytes.
            int offsetMapData = offsetTileAttribs;

            if (TileColorMode == ColorMode.PER_TILE)
            {
                offsetMapData += NumTiles;
            }

            MapData = Data.SubBuffer(offsetMapData, MapWidth * MapHeight);
            return(true);
        }
        private bool LoadVersion8(GR.Memory.ByteBuffer Data)
        {
            DisplayModeFile = (DisplayMode)Data.ByteAt(4);
            TileColorMode   = (ColorMode)Data.ByteAt(5);

            byte flags = Data.ByteAt(6);

            BackgroundColor  = Data.ByteAt(7);
            MultiColor1      = Data.ByteAt(8);
            MultiColor2      = Data.ByteAt(9);
            BackgroundColor4 = Data.ByteAt(10);

            BaseCellColorColorMatrix = Data.ByteAt(11);
            BaseCellColorScreenLo    = Data.ByteAt(12);
            BaseCellColorScreenHi    = Data.ByteAt(13);

            bool tileSysEnabled = ((flags & 0x01) != 0);


            ushort charDataBlockID      = 0xdab0;
            ushort charAttributeBlockID = 0xdab1;
            ushort charSetColorBlockID  = 0;
            ushort tileSetDataBlockID   = 0;
            ushort tileSetColorBlockID  = 0;
            ushort tileSetTagBlockID    = 0;
            ushort tileSetNameBlockID   = 0;
            ushort mapDataBlockID       = 0;

            int curBlockID = 0xdab2;

            if (TileColorMode == ColorMode.PER_CHAR)
            {
                charSetColorBlockID = (ushort)curBlockID++;
            }
            if (tileSysEnabled)
            {
                tileSetDataBlockID = (ushort)curBlockID++;
                if (TileColorMode == ColorMode.PER_TILE)
                {
                    tileSetColorBlockID = (ushort)curBlockID++;
                }
                tileSetTagBlockID  = (ushort)curBlockID++;
                tileSetNameBlockID = (ushort)curBlockID++;
            }
            mapDataBlockID = (ushort)curBlockID++;

            if (!tileSysEnabled)
            {
                // fake tiles (one per char)
                TileWidth  = 1;
                TileHeight = 1;
                NumTiles   = 256;

                for (int i = 0; i < NumTiles; ++i)
                {
                    Tile tile = new Tile();

                    tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                    tile.CharData.SetU16At(0, (ushort)i);

                    tile.ColorData.Resize((uint)(TileWidth * TileHeight));
                    tile.ColorData.SetU8At(0, (byte)CustomColor);

                    Tiles.Add(tile);
                }
            }

            var reader = Data.MemoryReader();

            reader.Skip(14);

            while (reader.DataAvailable)
            {
                ushort blockID = reader.ReadUInt16NetworkOrder();

                if (blockID == charDataBlockID)
                {
                    // Character data block

                    // CHARCNT: Character image count minus one( 16 - bit, LSBF ).
                    NumChars = reader.ReadUInt16() + 1;

                    // CHARDAT : Character image data( eight bytes / rows per image for CHARCNT images, rows are in TB order ).
                    for (int charIndex = 0; charIndex < NumChars; ++charIndex)
                    {
                        SingleChar newChar = new SingleChar();
                        newChar.Data  = new GR.Memory.ByteBuffer();
                        newChar.Color = CustomColor;
                        reader.ReadBlock(newChar.Data, 8);
                        Characters.Add(newChar);
                    }

                    if (!tileSysEnabled)
                    {
                        if (NumChars < 256)
                        {
                            // add all chars for safety reasons
                            for (int i = NumChars; i < 256; ++i)
                            {
                                SingleChar newChar = new SingleChar();
                                newChar.Data  = new GR.Memory.ByteBuffer(8);
                                newChar.Color = CustomColor;

                                Characters.Add(newChar);
                            }
                        }
                    }
                }
                else if (blockID == charAttributeBlockID)
                {
                    // char attributes
                    // BLKMARK: Block marker(0xDA, 0xB1).
                    // CHARATTS: Char attribute data, one byte per char image for CHARCNT images, low nybble = colour, high nybble = material.
                    //           nb.colours are only stored when the colouring mode is "per character".
                    for (int charIndex = 0; charIndex < NumChars; ++charIndex)
                    {
                        if (TileColorMode == ColorMode.PER_CHAR)
                        {
                            Characters[charIndex].Color = reader.ReadUInt8() & 0x0f;
                            if (!tileSysEnabled)
                            {
                                Tiles[charIndex].ColorData.SetU8At(0, (byte)Characters[charIndex].Color);
                            }
                        }
                    }
                }
                else if (blockID == charSetColorBlockID)
                {
                    // Character set colours block (only present if the project uses per-char colouring)...
                    //
                    // BLKMARK         : Block marker (0xDA, 0xBn).
                    // MTRXCOLRS_CHARS : Char colour data, 1-3 bytes per char image for CHARCNT images...
                    //
                    //    Colour_CmLo : Colour Matrix Low nybble (0-15) (not present if DISP_MODE is Bitmap_HR).
                    //    Colour_SmLo : Screen Matrix Low nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC).
                    //    Colour_SmHi : Screen Matrix High nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC).
                    //
                    //    Notes:-
                    //    - The colours in this block are intended for transfer to the C64 colour RAM cells and/or screen RAM cells.
                    //    - The usage / usefulness of a colour will depend on the display mode.
                    //    - Only the low nybbles of each byte are currently used, each provides a colour 0-15.

                    for (int i = 0; i < NumChars; ++i)
                    {
                        if (DisplayModeFile != DisplayMode.BITMAP_HIRES)
                        {
                            Characters[i].Color = reader.ReadUInt8();
                        }
                        if ((DisplayModeFile == DisplayMode.BITMAP_MC) ||
                            (DisplayModeFile == DisplayMode.BITMAP_HIRES))
                        {
                            // screen color lo
                            reader.ReadUInt8();
                            // screen color hi
                            reader.ReadUInt8();
                        }
                        if (!tileSysEnabled)
                        {
                            // use the charset color for our faked tiles
                            Tiles[i].ColorData.SetU8At(0, (byte)Characters[i].Color);
                        }
                    }
                }
                else if (blockID == tileSetDataBlockID)
                {
                    // Tile data block

                    // TILECNT: Tile count minus one(16 - bit, LSBF).
                    NumTiles = reader.ReadUInt16() + 1;

                    // TILEWID: Tile width( byte).
                    TileWidth = reader.ReadUInt8();
                    // TILEHEI: Tile height( byte).
                    TileHeight = reader.ReadUInt8();

                    // TILEDAT: Tile data, 16 bits per tile cell( LSBF) for TILEWID* TILEHEI cells * TILECNT items, cells are in LRTB order.
                    for (int i = 0; i < NumTiles; ++i)
                    {
                        Tile tile = new Tile();

                        tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                        tile.ColorData.Resize((uint)(TileWidth * TileHeight));

                        Tiles.Add(tile);
                    }
                    if (NumChars < 256)
                    {
                        // add all chars for safety reasons
                        for (int i = NumChars; i < 256; ++i)
                        {
                            SingleChar newChar = new SingleChar();
                            newChar.Data = new GR.Memory.ByteBuffer(8);
                            Characters.Add(newChar);
                        }
                    }
                    for (int i = 0; i < NumTiles; ++i)
                    {
                        for (int j = 0; j < TileWidth * TileHeight; ++j)
                        {
                            Tiles[i].CharData.SetU16At(j * 2, reader.ReadUInt16());
                        }
                    }
                }
                else if (blockID == tileSetColorBlockID)
                {
                    // Tile color block

                    // BLKMARK         : Block marker (0xDA, 0xBn).
                    // MTRXCOLRS_TILES : Tile colour data, 1-3 bytes per tile for TILECNT tiles...
                    //
                    //    Colour_CmLo : Colour Matrix Low nybble (0-15) (not present if DISP_MODE is Bitmap_HR).
                    //    Colour_SmLo : Screen Matrix Low nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC).
                    //    Colour_SmHi : Screen Matrix High nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC).
                    //
                    //    Notes:-
                    //    - The colours in this block are intended for transfer to the C64 colour RAM cells and/or screen RAM cells.
                    //    - The usage / usefulness of a colour will depend on the display mode.
                    //    - Only the low nybbles of each byte are currently used, each provides a colour 0-15.

                    for (int i = 0; i < NumTiles; ++i)
                    {
                        if (DisplayModeFile != DisplayMode.BITMAP_HIRES)
                        {
                            // tile generic color
                            reader.ReadUInt8();
                        }
                        if ((DisplayModeFile == DisplayMode.BITMAP_MC) ||
                            (DisplayModeFile == DisplayMode.BITMAP_HIRES))
                        {
                            // screen color lo
                            reader.ReadUInt8();
                            // screen color hi
                            reader.ReadUInt8();
                        }
                    }
                }
                else if (blockID == tileSetTagBlockID)
                {
                    // BLKMARK  : Block marker (0xDA, 0xBn).
                    // TILETAGS : Tile tag values, one byte per tile for TILECNT items.
                    for (int i = 0; i < NumTiles; ++i)
                    {
                        byte tileTag = reader.ReadUInt8();
                    }
                }
                else if (blockID == tileSetNameBlockID)
                {
                    // BLKMARK  : Block marker (0xDA, 0xBn).
                    // TILETAGS : Tile tag values, one byte per tile for TILECNT items.
                    for (int i = 0; i < NumTiles; ++i)
                    {
                        // zero terminated strings (urgh)
                        string name = "";
                        char   c    = (char)0;
                        do
                        {
                            c = (char)reader.ReadUInt8();
                            if (c != 0)
                            {
                                name += c;
                            }
                        }while (c != 0);
                        Tiles[i].Name = name;
                    }
                }
                else if (blockID == mapDataBlockID)
                {
                    // BLKMARK : Block marker (0xDA, 0xBn).
                    // MAPWID: Map Width(16 - bit, LSBF).
                    // MAPHEI: Map height(16 - bit, LSBF).
                    // MAPDAT: Map data, 16 bits per cell( LSBF ) for MAPWID* MAPHEI cells, cells are in LRTB order.
                    MapWidth  = reader.ReadUInt16();
                    MapHeight = reader.ReadUInt16();

                    MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight));
                    if (!tileSysEnabled)
                    {
                        // map has color data
                        MapColorData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight));
                    }

                    for (int i = 0; i < MapHeight; ++i)
                    {
                        for (int j = 0; j < MapWidth; ++j)
                        {
                            ushort mapData = reader.ReadUInt16();

                            // we only support 8 bytes per char
                            MapData.SetU8At(i * MapWidth + j, (byte)mapData); // do we?? Mega65!

                            if (TileColorMode == ColorMode.PER_CHAR)
                            {
                                MapColorData.SetU8At(i * MapWidth + j, (byte)Characters[(byte)mapData].Color);
                            }
                        }
                    }
                }
                else
                {
                    Debug.Log("Unexpected block ID: " + blockID.ToString("X"));
                    return(false);
                }
            }
            return(true);
        }
        private bool LoadVersion7(GR.Memory.ByteBuffer Data)
        {
            BackgroundColor  = Data.ByteAt(4);
            MultiColor1      = Data.ByteAt(5);
            MultiColor2      = Data.ByteAt(6);
            BackgroundColor4 = Data.ByteAt(7);
            CustomColor      = Data.ByteAt(8);
            TileColorMode    = (ColorMode)Data.ByteAt(9);

            // only uses values 0 to 2, which maps fine
            DisplayModeFile = (DisplayMode)Data.ByteAt(10);

            byte flags          = Data.ByteAt(11);
            bool tileSysEnabled = ((flags & 0x01) != 0);


            ushort charDataBlockID      = 0xdab0;
            ushort charAttributeBlockID = 0xdab1;
            ushort mapDataBlockID       = 0xdab2;


            if (!tileSysEnabled)
            {
                // fake tiles (one per char)
                TileWidth  = 1;
                TileHeight = 1;
                NumTiles   = 256;

                for (int i = 0; i < NumTiles; ++i)
                {
                    Tile tile = new Tile();

                    tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                    tile.CharData.SetU16At(0, (ushort)i);

                    tile.ColorData.Resize((uint)(TileWidth * TileHeight));
                    tile.ColorData.SetU8At(0, (byte)CustomColor);

                    Tiles.Add(tile);
                }
            }

            var reader = Data.MemoryReader();

            reader.Skip(12);

            while (reader.DataAvailable)
            {
                ushort blockID = reader.ReadUInt16NetworkOrder();

                if (blockID == mapDataBlockID)
                {
                    if (tileSysEnabled)
                    {
                        // Tile data block

                        // TILECNT: Tile count minus one(16 - bit, LSBF).
                        NumTiles = reader.ReadUInt16() + 1;

                        // TILEWID: Tile width( byte).
                        TileWidth = reader.ReadUInt8();
                        // TILEHEI: Tile height( byte).
                        TileHeight = reader.ReadUInt8();

                        // TILEDAT: Tile data, 16 bits per tile cell( LSBF) for TILEWID* TILEHEI cells * TILECNT items, cells are in LRTB order.
                        for (int i = 0; i < NumTiles; ++i)
                        {
                            Tile tile = new Tile();

                            tile.CharData.Resize((uint)(TileWidth * TileHeight * 2));
                            tile.ColorData.Resize((uint)(TileWidth * TileHeight));

                            Tiles.Add(tile);
                        }
                        if (NumChars < 256)
                        {
                            // add all chars for safety reasons
                            for (int i = NumChars; i < 256; ++i)
                            {
                                SingleChar newChar = new SingleChar();
                                newChar.Data = new GR.Memory.ByteBuffer(8);
                                Characters.Add(newChar);
                            }
                        }
                        for (int i = 0; i < NumTiles; ++i)
                        {
                            for (int j = 0; j < TileWidth * TileHeight; ++j)
                            {
                                Tiles[i].CharData.SetU16At(j * 2, reader.ReadUInt16());
                            }
                        }
                    }
                    else
                    {
                        // BLKMARK : Block marker (0xDA, 0xBn).
                        // MAPWID: Map Width(16 - bit, LSBF).
                        // MAPHEI: Map height(16 - bit, LSBF).
                        // MAPDAT: Map data, 16 bits per cell( LSBF ) for MAPWID* MAPHEI cells, cells are in LRTB order.
                        MapWidth  = reader.ReadUInt16();
                        MapHeight = reader.ReadUInt16();

                        MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight));

                        for (int i = 0; i < MapHeight; ++i)
                        {
                            for (int j = 0; j < MapWidth; ++j)
                            {
                                MapData.SetU8At(i * MapWidth + j, (byte)reader.ReadUInt16());
                            }
                        }
                    }
                }

                if (blockID == charDataBlockID)
                {
                    // Character data block

                    // CHARCNT: Character image count minus one( 16 - bit, LSBF ).
                    NumChars = reader.ReadUInt16() + 1;

                    // CHARDAT : Character image data( eight bytes / rows per image for CHARCNT images, rows are in TB order ).
                    for (int charIndex = 0; charIndex < NumChars; ++charIndex)
                    {
                        SingleChar newChar = new SingleChar();
                        newChar.Data  = new GR.Memory.ByteBuffer();
                        newChar.Color = CustomColor;
                        reader.ReadBlock(newChar.Data, 8);
                        Characters.Add(newChar);
                    }

                    if (!tileSysEnabled)
                    {
                        if (NumChars < 256)
                        {
                            // add all chars for safety reasons
                            for (int i = NumChars; i < 256; ++i)
                            {
                                SingleChar newChar = new SingleChar();
                                newChar.Data  = new GR.Memory.ByteBuffer(8);
                                newChar.Color = CustomColor;

                                Characters.Add(newChar);
                            }
                        }
                    }
                }
                else if (blockID == charAttributeBlockID)
                {
                    // char attributes
                    // BLKMARK: Block marker(0xDA, 0xB1).
                    // CHARATTS: Char attribute data, one byte per char image for CHARCNT images, low nybble = colour, high nybble = material.
                    //           nb.colours are only stored when the colouring mode is "per character".
                    for (int charIndex = 0; charIndex < NumChars; ++charIndex)
                    {
                        if (TileColorMode == ColorMode.PER_CHAR)
                        {
                            Characters[charIndex].Color = reader.ReadUInt8() & 0x0f;
                            if (!tileSysEnabled)
                            {
                                Tiles[charIndex].ColorData.SetU8At(0, (byte)Characters[charIndex].Color);
                            }
                        }
                    }
                }
            }
            return(true);
        }