Example #1
0
        static void Dump8x8Tiles(Rom rom, int gfxaddress, int tiles, int pos, byte palette, Color[] customPalette, bool transparency = false)
        {
            for (int n = 0; n < tiles; n++)
            {
                int tilePosX = ((n + pos) % 16) * 8;
                int tilePosY = ((n + pos) / 16) * 8;

                for (int y = 0; y < 8; y++)
                {
                    byte data0     = rom.ReadByte(gfxaddress++);
                    byte data1     = rom.ReadByte(gfxaddress++);
                    int  destIndex = tilePosX + (y + tilePosY) * tiles8x8.Width;

                    for (int x = 0; x < 8; x++)
                    {
                        int pixelA = (data0 >> (7 - x)) & 0x1;
                        int pixelB = (data1 >> (7 - x)) & 0x1;
                        int pixel  = pixelA + pixelB * 2;

                        if (!transparency || pixel != 0)
                        {
                            int palindex = (palette >> pixel * 2) & 0x3;
                            tiles8x8.Bits[destIndex + x] = customPalette[palindex].ToArgb();
                        }
                    }
                }
            }
        }
Example #2
0
        static byte[] RLEDecompressTiles(Rom rom, int tilesdata)
        {
            byte[] decompressed = new byte[0x3000];
            int    position     = 0;

            while (position < decompressed.Length)
            {
                byte data = rom.ReadByte(tilesdata++);
                if ((data & 0x80) == 0x80)
                {
                    data = (byte)(data & 0x7F);
                    byte rep = rom.ReadByte(tilesdata++);
                    for (int j = 0; j <= rep; j++)
                    {
                        decompressed[position++] = data;
                    }
                }
                else
                {
                    decompressed[position++] = data;
                }
            }

            return(decompressed);
        }
Example #3
0
        static bool LoadEnemiesTiles(Rom rom, int enemyIndex, int spriteDataAddress, int tilesDataAddress)
        {
            int index = 0;

            do
            {
                rom.SetBank(0x7);
                int tilesBank    = rom.ReadByte(tilesDataAddress++);
                int tilesAddress = rom.ReadWord(tilesDataAddress++); tilesDataAddress++;
                int tilesCount   = rom.ReadByte(tilesDataAddress++);

                if (tilesCount == 0xFF)
                {
                    return(false);
                }

                if (index == enemyIndex)
                {
                    LoadEnemiesTilesInternal(rom, spriteDataAddress, tilesBank, tilesCount, tilesAddress);
                    return(true);
                }

                index++;
            }while(true);
        }
Example #4
0
        public static void SaveBlocksToRom(Rom rom, int course)
        {
            //grab all levels data at once
            byte[][] allTiles = new byte[0x2B][];

            for (int i = 0; i < 0x2B; i++)
            {
                rom.SetBank(0xC);
                int headerposition = rom.ReadWord(0x4560 + i * 2);
                int tilebank       = rom.ReadByte(headerposition + 9);
                int tilesubbank    = rom.ReadByte(headerposition + 10);

                rom.SetBank(tilebank);
                int    tilePosition = rom.ReadWord(0x4000 + tilesubbank * 2);
                byte[] tileData     = RLEDecompressTiles(rom, tilePosition);
                allTiles[i] = tileData;
            }

            Array.Copy(levelData, allTiles[course], 0x3000);

            //write them back to ROM
            byte bank          = 0x20;
            byte subbank       = 0;
            int  writePosition = 0x4040;            //first 64 bytes are reserved for level pointers

            for (int i = 0; i < 0x2B; i++)
            {
                byte[] tileData = RLECompressTiles(allTiles[i]).ToArray();
                if ((writePosition + tileData.Length) >= 0x8000 || subbank >= 32)
                {
                    //no more space, switch to another bank
                    bank++;
                    subbank       = 0;
                    writePosition = 0x4040;
                }

                //write data to bank
                rom.SetBank(bank);
                rom.WriteWord(0x4000 + subbank * 2, (ushort)writePosition);
                rom.WriteBytes(writePosition, tileData);

                //update level header
                rom.SetBank(0xC);
                int headerposition = rom.ReadWord(0x4560 + i * 2);
                rom.WriteByte(headerposition + 9, bank);
                rom.WriteByte(headerposition + 10, subbank);

                subbank++;
                writePosition += tileData.Length;
            }
        }
Example #5
0
        static void Dump16x16Tiles(Rom rom, int tileindexaddress, int switchMode, Color defaultColor, out bool[] anim16x16Tiles, out int[] anim8x8Tiles)
        {
            anim16x16Tiles = new bool[16 * 8];
            anim8x8Tiles   = new int[16 * 8 * 2 * 2];

            int m = 0;

            for (int n = 0; n < 16; n++)
            {
                for (int i = 0; i < 8; i++)
                {
                    int tileIndex    = i + n * 8;
                    int newTileIndex = SwitchTile(tileIndex, switchMode);

                    bool isAnimatedTile = false;
                    for (int k = 0; k < 2; k++)
                    {
                        for (int j = 0; j < 2; j++)
                        {
                            byte subTileIndex = rom.ReadByte(tileindexaddress + newTileIndex * 4 + k * 2 + j);
                            bool isAnimated   = subTileIndex >= (2 * 16) && subTileIndex < (2 * 16 + 4);
                            isAnimatedTile       |= isAnimated;
                            animated8x8Tiles[m++] = isAnimated ? subTileIndex : -1;

                            Point dest = new Point(j * 8 + i * 16, k * 8 + n * 16);
                            Dump8x8Tile(dest, subTileIndex, defaultColor);
                        }
                    }

                    anim16x16Tiles[tileIndex] = isAnimatedTile;
                }
            }
        }
Example #6
0
        static void LoadEnemiesTilesInternal(Rom rom, int spriteDataAddress, int tilesBank, int tilesCount, int tilesAddress)
        {
            rom.SetBank(tilesBank);
            int pos         = rom.ReadWord(spriteDataAddress);
            int spriteFlags = rom.ReadByte(pos);
            int palette     = (spriteFlags & 0x10) != 0 ? 0xD1 : 0x1E;

            Array.Clear(tiles8x8.Bits, 0, tiles8x8.Bits.Length);
            Dump8x8Tiles(rom, tilesAddress, tilesCount, 0, (byte)palette, enemyPalette, true);
        }
Example #7
0
        static byte[] RLEDecompressObjects(Rom rom, int enemiesData)
        {
            int position = 0;

            byte[] decompressed = new byte[0x2000];

            while (position < decompressed.Length)
            {
                byte data = rom.ReadByte(enemiesData++);
                decompressed[position++] = (byte)(data >> 4);
                decompressed[position++] = (byte)(data & 0xF);

                byte repeat = rom.ReadByte(enemiesData++);
                for (int i = 0; i < repeat; i++)
                {
                    decompressed[position++] = 0;
                    decompressed[position++] = 0;
                }
            }

            return(decompressed);
        }
Example #8
0
        public static void Dump8x8Tiles(Rom rom, int gfxaddress, Bitmap gfx8, int tiles, int rowpos, byte palette)
        {
            for(int n = 0 ; n < tiles ; n++)
            {
                for(int j = 0 ; j < 8 ; j++)
                {
                    byte data0 = rom.ReadByte(gfxaddress++);
                    byte data1 = rom.ReadByte(gfxaddress++);

                    for(int i = 0 ; i < 8 ; i++)
                    {
                        int pixelA = (data0 >> (7 - i)) & 0x1;
                        int pixelB = (data1 >> (7 - i)) & 0x1;
                        int pixel = pixelA + pixelB * 2;
                        int palindex = (palette >> pixel * 2) & 0x3;

                        int x = i + n%16 * 8;
                        int y = j + (n/16 + rowpos) * 8;

                        gfx8.SetPixel(x, y, paletteColors[palindex]);
                    }
                }
            }
        }
Example #9
0
        static Rectangle DumpSpritePlayer(Rom rom, int posx, int posy, int spriteAddress, bool horizontalFlip)
        {
            Rectangle rectangle = Rectangle.Empty;
            int       pos       = spriteAddress;

            Func <sbyte, sbyte> hflip = x => (sbyte)(horizontalFlip ? ((~(sbyte)x) - 7) : x);

            pos = rom.ReadWord(pos);
            while (rom.ReadByte(pos) != 0x80)
            {
                int spx, spy;
                unchecked
                {
                    spy = (sbyte)rom.ReadByte(pos++) + posy;
                    spx = hflip((sbyte)rom.ReadByte(pos++)) + posx;
                }
                int spriteIndex = rom.ReadByte(pos++);
                int spriteFlags = rom.ReadByte(pos++) ^ (horizontalFlip ? 0x40 : 0x00);

                DumpSpriteInternal(spx, spy, spriteIndex, spriteFlags, playerSprite, ref rectangle);
            }

            return(rectangle);
        }
Example #10
0
        static Rectangle DumpSprite(Rom rom, int posx, int posy, int spriteAddress, DirectBitmap tilesDest)
        {
            Rectangle rectangle = Rectangle.Empty;
            int       pos       = spriteAddress;

            pos = rom.ReadWord(pos);
            pos++;             //skip sprite flags

            while (rom.ReadByte(pos) != 0x80)
            {
                int spx, spy;
                unchecked
                {
                    spy = (sbyte)rom.ReadByte(pos++) + posy;
                    spx = (sbyte)rom.ReadByte(pos++) + posx;
                }
                int spriteData  = rom.ReadByte(pos++);
                int spriteIndex = (spriteData & 0x3F);

                DumpSpriteInternal(spx, spy, spriteIndex, spriteData, tilesDest, ref rectangle);
            }

            return(rectangle);
        }
Example #11
0
        public static int SearchWarp(Rom rom, int course, int sector)
        {
            rom.SetBank(0xC);
            //search sector that target that sector
            for (int i = 0; i < 32; i++)
            {
                int warp = rom.ReadWord(0x4F30 + course * 64 + i * 2);

                if (rom.ReadByte(warp) == sector)
                {
                    return(warp);
                }
            }

            return(-1);
        }
Example #12
0
        public static void Dump16x16Tiles(Rom rom, int tileindexaddress, Bitmap gfx8, Graphics g, bool switchA, bool switchB)
        {
            for(int n = 0 ; n < 16 ; n++)
            {
                for(int i = 0 ; i < 8 ; i++)
                {
                    int tileIndex = i + n * 8;
                    tileIndex = Level.Switch(tileIndex, switchA, switchB);

                    for(int k = 0 ; k < 2 ; k++)
                    {
                        for(int j = 0 ; j < 2 ; j++)
                        {
                            byte subTileIndex = rom.ReadByte(tileindexaddress + tileIndex * 4 + k * 2 + j);

                            g.DrawImage(gfx8,
                                    new Rectangle(j * 8 + i * 16, k * 8 + n * 16, 8, 8),
                                    new Rectangle((subTileIndex % 16) * 8, ((subTileIndex) / 16) * 8, 8, 8),
                                    GraphicsUnit.Pixel);
                        }
                    }
                }
            }
        }
Example #13
0
        static void FindEnemiesData(Rom rom, int enemiesPointer, out int enemyId, out int tilesPointer)
        {
            byte[] pattern =
            {
                0x3E, 0x00,                       //ld  a, ..
                0xEA, 0x2F, 0xA3,                 //ld  (A32F),a
                0x3E, 0x00,                       //ld  a, ..
                0xEA, 0x30, 0xA3,                 //ld  (A330),a
                0x01, 0x00, 0x00,                 //ld  bc, ..
                0xCD, 0xA7, 0x40                  //call 40A7
            };

            rom.SetBank(0x7);
            int position = enemiesPointer;

            while (rom.ReadByte(position) != 0xC9)            //ret
            {
                bool match = true;
                for (int j = 0; j < pattern.Length; j++)
                {
                    byte valueFromRom   = rom.ReadByte(position + j);
                    byte valueToCompare = pattern[j];

                    if (valueToCompare != 0x00 && valueFromRom != valueToCompare)
                    {
                        match = false;
                        break;
                    }
                }

                if (match)
                {
                    enemyId      = rom.ReadByte(position + 6) << 8 | rom.ReadByte(position + 1);
                    tilesPointer = rom.ReadByte(position + 12) << 8 | rom.ReadByte(position + 11);
                    return;
                }

                position++;
            }

            throw new Exception("cannot find enemies data");
        }
Example #14
0
        public static int SearchWarp(Rom rom, int course, int sector)
        {
            rom.SetBank(0xC);
            int warp = rom.ReadWord(0x4F30 + course * 64 + sector * 2);
            if(rom.ReadByte(warp) != 32)
            {
                //search sector that target that sector
                for(int i = 0 ; i < 32 ; i++)
                {
                    warp = rom.ReadWord(0x4F30 + course * 64 + i * 2);

                    if(rom.ReadByte(warp) == sector)
                    {
                        return warp;
                    }
                }
            }

            return -1;
        }
Example #15
0
        public static void SaveBlocksToRom(Rom rom, int course)
        {
            //grab all levels data at once
            byte[][] allTiles = new byte[0x2B][];

            for(int i = 0 ; i < 0x2B ; i++)
            {
                rom.SetBank(0xC);
                int headerposition = rom.ReadWord(0x4560 + i * 2);
                int tilebank = rom.ReadByte(headerposition + 9);
                int tilesubbank = rom.ReadByte(headerposition + 10);

                rom.SetBank(tilebank);
                int tilePosition = rom.ReadWord(0x4000 + tilesubbank * 2);
                byte[] tileData = RLEDecompressTiles(rom, tilePosition).Take(0x3000).ToArray();
                allTiles[i] = tileData;
            }

            Array.Copy(levelData, allTiles[course], 0x3000);

            //write them back to ROM
            byte bank = 0x20;
            byte subbank = 0;
            int writePosition = 0x4040; //first 64 bytes are reserved for level pointers
            for(int i = 0 ; i < 0x2B ; i++)
            {
                byte[] tileData = RLECompressTiles(allTiles[i]).ToArray();
                if((writePosition + tileData.Length) >= 0x8000 || subbank >= 32)
                {
                    //no more space, switch to another bank
                    bank++;
                    subbank = 0;
                    writePosition = 0x4040;
                }

                //write data to bank
                rom.SetBank(bank);
                rom.WriteWord(0x4000 + subbank * 2, (ushort)writePosition);
                rom.WriteBytes(writePosition, tileData);

                //update level header
                rom.SetBank(0xC);
                int headerposition = rom.ReadWord(0x4560 + i * 2);
                rom.WriteByte(headerposition + 9, bank);
                rom.WriteByte(headerposition + 10, subbank);

                subbank++;
                writePosition += tileData.Length;
            }
        }
Example #16
0
 public static IEnumerable<byte> RLEDecompressTiles(Rom rom, int tilesdata)
 {
     while(true)
     {
         byte data = rom.ReadByte(tilesdata++);
         if((data & 0x80) == 0x80)
         {
             data = (byte)(data & 0x7F);
             byte rep = rom.ReadByte(tilesdata++);
             for(int j = 0 ; j <= rep ; j++)
             {
                 yield return data;
             }
         }
         else
         {
             yield return data;
         }
     }
 }
Example #17
0
        public static IEnumerable<byte> RLEDecompressObjects(Rom rom, int enemiesData)
        {
            while(true)
            {
                byte data = rom.ReadByte(enemiesData++);
                yield return (byte)(data >> 4);
                yield return (byte)(data & 0xF);

                byte repeat = rom.ReadByte(enemiesData++);
                for(int i = 0 ; i < repeat ; i++)
                {
                    yield return 0;
                    yield return 0;
                }
            }
        }
Example #18
0
        public static void DumpLevel(Rom rom, int course, int warp, Bitmap tiles8x8, Bitmap tiles16x16, bool reloadAll, bool switchA, bool switchB, int paletteIndex)
        {
            rom.SetBank(0xC);
            int header = rom.ReadWord(0x4560 + course * 2);

            int tilebank = rom.ReadByte(header + 0);
            int tileaddressB = rom.ReadWord(header + 1);
            int tileaddressA = rom.ReadWord(header + 3);
            int tileanimated = rom.ReadWord(header + 7);

            int blockbank = rom.ReadByte(header + 9);
            int blockubbank = rom.ReadByte(header + 10);
            int blockindex = rom.ReadWord(header + 11);
            byte palette = rom.ReadByte(header + 27);

            //load warp
            if(warp != -1)
            {
                tilebank = rom.ReadByte(warp + 11);
                tileaddressB = rom.ReadWord(warp + 12);
                tileaddressA = rom.ReadWord(warp + 14);
                tileanimated = rom.ReadWord(warp + 18);
                blockindex = rom.ReadWord(warp + 20);
                palette = rom.ReadByte(warp + 10);
            }

            //set palette
            paletteColors = palettes[paletteIndex];

            //dump 8x8 blocks
              	using(Graphics g = Graphics.FromImage(tiles8x8))
              	{
              		g.Clear(paletteColors[0]);
              		rom.SetBank(0x11);
                Dump8x8Tiles(rom, tileaddressA, tiles8x8, 2*16, 0, palette);
                rom.SetBank(tilebank);
                Dump8x8Tiles(rom, tileaddressB, tiles8x8, 6*16, 2, palette);
                rom.SetBank(0x11);
                Dump8x8Tiles(rom, tileanimated, tiles8x8, 4, 2, palette);

              	}

            //dump 16x16 blocks
              	using(Graphics g = Graphics.FromImage(tiles16x16))
              	{
              		g.Clear(paletteColors[0]);
                rom.SetBank(0xB);
                Dump16x16Tiles(rom, blockindex, tiles8x8, g, switchA, switchB);
              	}

              	if(reloadAll)
              	{
              	//dump level
              		rom.SetBank(blockbank);
                int tilesdata = rom.ReadWord(0x4000 + blockubbank * 2);
                levelData = RLEDecompressTiles(rom, tilesdata).Take(0x3000).ToArray();

                //dump scroll
                rom.SetBank(0xC);
                scrollData = rom.ReadBytes(0x4000 + course * 32, 32);

                //dump objects
                rom.SetBank(0x7);
                int objectsPosition = rom.ReadWord(0x4199 + course * 2);
                objectsData = RLEDecompressObjects(rom, objectsPosition).Take(0x2000).ToArray();

                //dump warps
                rom.SetBank(0xC);
                warps = new Byte[32];
                for(int i = 0 ; i < 32 ; i++)
                {
                    int warpdata = rom.ReadWord(0x4F30 + course * 64 + i * 2);
                    warps[i] = rom.ReadByte(warpdata);
                }

                warioPosition = rom.ReadWordSwap(header + 15) + rom.ReadWordSwap(header + 13) * 8192;
              	}
        }
Example #19
0
        public static void DumpLevel(Rom rom, int course, int warp, bool reloadAll, int switchMode, int paletteIndex, int animatedTileIndex, bool reloadAnimatedTilesOnly)
        {
            int  tilebank;
            int  tileaddressB;
            int  tileaddressA;
            int  tileanimated;
            int  blockindex;
            byte palette;
            int  enemiesData;

            rom.SetBank(0xC);
            int header = rom.ReadWord(0x4560 + course * 2);

            if (warp != -1)
            {
                //load warp
                tilebank          = rom.ReadByte(warp + 11);
                tileaddressB      = rom.ReadWord(warp + 12);
                tileaddressA      = rom.ReadWord(warp + 14);
                tileanimated      = rom.ReadWord(warp + 18);
                blockindex        = rom.ReadWord(warp + 20);
                animatedTilesMask = rom.ReadByte(warp + 9);
                palette           = rom.ReadByte(warp + 10);
                enemiesData       = rom.ReadWord(warp + 22);
            }
            else
            {
                //or header
                tilebank          = rom.ReadByte(header + 0);
                tileaddressB      = rom.ReadWord(header + 1);
                tileaddressA      = rom.ReadWord(header + 3);
                tileanimated      = rom.ReadWord(header + 7);
                blockindex        = rom.ReadWord(header + 11);
                animatedTilesMask = rom.ReadByte(header + 26);
                palette           = rom.ReadByte(header + 27);
                enemiesData       = rom.ReadWord(header + 28);
            }

            Color[] paletteColors = palettes[paletteIndex];
            if (!reloadAnimatedTilesOnly)
            {
                int enemiesIdsPointer, enemiesTiles;
                FindEnemiesData(rom, enemiesData, out enemiesIdsPointer, out enemiesTiles);
                DumpEnemiesSprites(rom, enemiesIdsPointer, enemiesTiles);

                //dump 8x8 tiles
                Array.Clear(tiles8x8.Bits, 0, tiles8x8.Width * tiles8x8.Height);
                rom.SetBank(0x11);
                Dump8x8Tiles(rom, tileaddressA, 2 * 16, 0 * 16, palette, paletteColors);
                rom.SetBank(tilebank);
                Dump8x8Tiles(rom, tileaddressB, 6 * 16, 2 * 16, palette, paletteColors);
            }

            if (animatedTilesMask != 0)
            {
                rom.SetBank(0x11);
                Dump8x8Tiles(rom, tileanimated + animatedTileIndex * 16 * 4, 4, 2 * 16, palette, paletteColors);
            }

            //dump 16x16 tiles
            if (reloadAnimatedTilesOnly)
            {
                DumpAnimated16x16Tiles(paletteColors[0]);
            }
            else
            {
                rom.SetBank(0xB);
                Dump16x16Tiles(rom, blockindex, switchMode, paletteColors[0], out animated16x16Tiles, out animated8x8Tiles);
            }

            if (reloadAll)
            {
                //dump 16x16 blocks
                rom.SetBank(0xC);
                int blockbank   = rom.ReadByte(header + 9);
                int blockubbank = rom.ReadByte(header + 10);

                rom.SetBank(blockbank);
                int tilesdata = rom.ReadWord(0x4000 + blockubbank * 2);
                levelData = RLEDecompressTiles(rom, tilesdata);

                //dump scroll
                rom.SetBank(0xC);
                scrollData = rom.ReadBytes(0x4000 + course * 32, 32);

                //dump objects
                rom.SetBank(0x7);
                int objectsPosition = rom.ReadWord(0x4199 + course * 2);
                objectsData = RLEDecompressObjects(rom, objectsPosition);

                //dump warps
                rom.SetBank(0xC);
                warps = new Byte[32];
                for (int i = 0; i < 32; i++)
                {
                    int warpdata = rom.ReadWord(0x4F30 + course * 64 + i * 2);
                    warps[i] = rom.ReadByte(warpdata);
                }

                warioPosition    = rom.ReadWordSwap(header + 15) + rom.ReadWordSwap(header + 13) * 8192;
                warioRightFacing = (rom.ReadByte(header + 18) & 0x20) == 0;
            }
        }