Example #1
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 #2
0
        public static bool SaveObjectsToRom(Rom rom, int course, out string errorMessage)
        {
            byte[][] enemyData = new byte[0x2B][];

            //save objects
            rom.SetBank(0x7);
            for (int i = 0; i < 0x2B; i++)
            {
                int objectsPos = rom.ReadWord(0x4199 + i * 2);
                enemyData[i] = RLEDecompressObjects(rom, objectsPos);
            }
            enemyData[course] = objectsData;

            int objectSize = enemyData.Sum(x => RLECompressObjects(x).Count());

            if (objectSize > 4198)
            {
                errorMessage = string.Format("Object data is too big to fit in ROM.\r\nPlease remove some objects to free at least {0} byte(s).", objectSize - 4198);
                return(false);
            }

            int startPos = rom.ReadWord(0x4199);

            for (int i = 0; i < 0x2B; i++)
            {
                rom.WriteWord(0x4199 + i * 2, (ushort)startPos);

                byte[] data = RLECompressObjects(enemyData[i]).ToArray();
                rom.WriteBytes(startPos, data);
                startPos += data.Length;
            }

            errorMessage = string.Empty;
            return(true);
        }
Example #3
0
        static void DumpEnemiesSprites(Rom rom, int enemiesIdsPointer, int tilesDataAddress)
        {
            loadedSprites    = new Rectangle[6];
            enemiesAvailable = new bool[6];
            Array.Clear(tilesEnemies.Bits, 0, tilesEnemies.Bits.Length);

            for (int i = 0; i < 6; i++)
            {
                rom.SetBank(0x7);
                int enemyId = rom.ReadWord(enemiesIdsPointer + (i + 1) * 2);

                if (enemyId != 0x530F)
                {
                    enemiesAvailable[i] = true;
                    int spriteDataAddress;
                    if (enemiesIdsToSpriteData.TryGetValue(enemyId, out spriteDataAddress))
                    {
                        if (LoadEnemiesTiles(rom, i, spriteDataAddress, tilesDataAddress))
                        {
                            Rectangle rectangle = DumpSprite(rom, 32, 56 + i * 64, spriteDataAddress, tilesEnemies);
                            loadedSprites[i] = rectangle;
                        }
                    }
                }
            }
        }
Example #4
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 #5
0
        public static void DumpBonusSprites(Rom rom)
        {
            Array.Clear(tiles8x8.Bits, 0, tiles8x8.Bits.Length);
            //bonus sprites
            rom.SetBank(0x5);
            Dump8x8Tiles(rom, 0x4C81, 23, 0, 0x1E, enemyPalette, true);

            rom.SetBank(0x11);
            Dump8x8Tiles(rom, 0x7300, 4, 16 + 23, 0x1E, enemyPalette, true);

            rom.SetBank(0xF);
            int[] sprites = { 0x4ACB, 0x4AEB, 0x4ADB, 0x4AFB, 0x4B0B, 0x4B1B, 0x4B2B, 0x4B4B, 0x4B5B };
            for (int i = 0; i < sprites.Length; i++)
            {
                DumpSprite(rom, 8 + i * 16, 16, sprites[i], tilesObjects);
            }
        }
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
        public static void DumpPlayerSprite(Rom rom)
        {
            Array.Clear(tiles8x8.Bits, 0, tiles8x8.Bits.Length);

            rom.SetBank(0x5);
            Dump8x8Tiles(rom, 0x42F1, 64, 0, 0x1E, enemyPalette, true);
            playerRectangles = new []
            {
                DumpSpritePlayer(rom, 32, 56, 0x603B, false),
                DumpSpritePlayer(rom, 32, 56 + 64, 0x603B, true)
            };
        }
Example #8
0
        public static List <KeyValuePair <int, int> > GetCourseIds(Rom rom)
        {
            //convert course id => course no using data in ROM
            rom.SetBank(0);
            var courseIdToNo = new List <KeyValuePair <int, int> >();

            for (int i = 0; i <= 0x2A; i++)
            {
                int levelpointer = rom.ReadWord(0x0534 + i * 2);
                int courseNo     = (levelpointer - 0x0587) / 3;
                courseIdToNo.Add(new KeyValuePair <int, int>(i, courseNo));
            }

            return(courseIdToNo);
        }
Example #9
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 #10
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 #11
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 #12
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 #13
0
        public static bool SaveObjectsToRom(Rom rom, int course, out string errorMessage)
        {
            byte[][] enemyData = new byte[0x2B][];

            //save objects
            rom.SetBank(0x7);
            for(int i = 0 ; i < 0x2B ; i++)
            {
                int objectsPos = rom.ReadWord(0x4199 + i * 2);
                enemyData[i] = RLEDecompressObjects(rom, objectsPos).Take(0x2000).ToArray();
            }
            enemyData[course]= objectsData;

            int objectSize = enemyData.Sum(x => RLECompressObjects(x).Count());
            if(objectSize > 4198)
            {
                errorMessage = string.Format("Object data is too big to fit in ROM.\r\nPlease remove at least {0} byte(s).", objectSize - 4198);
                return false;
            }

            int startPos = rom.ReadWord(0x4199);
            for(int i = 0 ; i < 0x2B ; i++)
            {
                rom.WriteWord(0x4199 + i * 2, (ushort)startPos);

                byte[] data = RLECompressObjects(enemyData[i]).ToArray();
                rom.WriteBytes(startPos, data);
                startPos += data.Length;
            }

            errorMessage = string.Empty;
            return true;
        }
Example #14
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 #15
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;
            }
        }