public /*override*/ void Write() { m_File.Write32(m_Offset + 0x00, m_FileID); m_File.Write16(m_Offset + 0x04, m_Bank); m_File.Write8(m_Offset + 0x06, m_Volume); m_File.Write8(m_Offset + 0x07, m_ChannelPriority); m_File.Write8(m_Offset + 0x08, m_PlayerPriority); m_File.Write8(m_Offset + 0x09, m_PlayerNumber); m_File.WriteBlock(m_Offset + 0x0A, m_Unknown2); }
private void UpdateEntries(String msg, int index) { m_MsgData[index] = msg; m_ShortVersions[index] = ShortVersion(msg, index); int lengthDif = EncodeString(msg).Count - m_StringLengths[index]; m_StringLengths[index] += lengthDif; //Make or remove room for the new string if needed (don't need to for last entry) if (lengthDif > 0 && index != m_MsgData.Length - 1) { uint curStringStart = m_StringHeaderData[index] + m_DAT1Start; uint nextStringStart = m_StringHeaderData[index + 1] + m_DAT1Start; byte[] followingData = file.ReadBlock(nextStringStart, (uint)(file.m_Data.Length - nextStringStart)); for (int i = (int)curStringStart; i < (int)nextStringStart + lengthDif; i++) { file.Write8((uint)i, 0);// Fill the gap with zeroes } file.WriteBlock((uint)(nextStringStart + lengthDif), followingData); } else if (lengthDif < 0 && index != m_MsgData.Length - 1) { // lengthDif is negative, -- + uint nextStringStart = m_StringHeaderData[index + 1] + m_DAT1Start; byte[] followingData = file.ReadBlock(nextStringStart, (uint)(file.m_Data.Length - nextStringStart)); file.WriteBlock((uint)(nextStringStart + lengthDif), followingData); int oldSize = file.m_Data.Length; Array.Resize(ref file.m_Data, oldSize + lengthDif);// Remove duplicate data at end of file } // Update pointers to string entry data if (lengthDif != 0) { for (int i = index + 1; i < m_MsgData.Length; i++) { if (lengthDif > 0) { m_StringHeaderData[i] += (uint)lengthDif; } else if (lengthDif < 0) { m_StringHeaderData[i] = (uint)(m_StringHeaderData[i] + lengthDif); } file.Write32(m_StringHeaderAddr[i], m_StringHeaderData[i]); file.Write16(m_StringWidthAddr[i], m_StringWidth[i]); file.Write16(m_StringHeightAddr[i], m_StringHeight[i]); } } // Update total file size file.Write32(0x08, (uint)(int)(file.Read32(0x08) + lengthDif)); // Update DAT1 size file.Write32(m_DAT1Start - 0x04, (uint)(int)(file.Read32(m_DAT1Start - 0x04) + lengthDif)); }
public void SwitchBackground(int swapped) { m_PalFile = Program.m_ROM.GetFileFromName(txtSelNCL.Text); //The background colour is the first colour stored in the palette ushort first = m_PalFile.Read16((uint)0); //Read the first colour in the palette file ushort swappedColour = m_PalFile.Read16((uint)(swapped * 2)); //Read the colour to be swapped //Colour in BGR15 format (16 bits) written to every even address 0,2,4... m_PalFile.Write16((uint)0, swappedColour); //Write new background colour to first entry m_PalFile.Write16((uint)(swapped * 2), first); //Write the previously first colour to the colour being swapped m_PalFile.SaveChanges(); //Swap all palette file entries for the swapped colours in the graphic file m_TileSetFile = Program.m_ROM.GetFileFromName(txtSelNCG.Text); if (chkNCGDcmp.Checked) { m_TileSetFile.ForceDecompression(); } uint tileoffset = 0, tilenum = 0; ushort tilecrap = 0; for (int my = 0; my < m_SizeY; my += 8) { for (int mx = 0; mx < m_SizeX; mx += 8) { if (m_IsUsingTileMap) { tilecrap = m_TileMapFile.Read16(tileoffset); tilenum = (uint)(tilecrap & 0x03FF); } for (int ty = 0; ty < 8; ty++) { for (int tx = 0; tx < 8; tx++) { if (m_BPP == 8) { uint totaloffset = (uint)(tilenum * 64 + ty * 8 + tx); //Position of current pixel's entry byte palentry = m_TileSetFile.Read8(totaloffset); if (palentry == 0) //If the current pixel points to first colour in palette, { m_TileSetFile.Write8(totaloffset, (byte)(swapped)); //point it to the swapped colour } if (palentry == (byte)swapped) //If the current pixel points to the swapped colour in palette, { m_TileSetFile.Write8(totaloffset, (byte)0); //point it to the first colour } } else if (m_BPP == 4) { float totaloffset = (float)((float)(tilenum * 64 + ty * 8 + tx) / 2f);//Address of current pixel byte palentry = 0; if (totaloffset % 1 == 0) { // Right 4 bits palentry = m_TileSetFile.Read8((uint)totaloffset); //Offset of current pixel's entry in palette file palentry = (byte)(palentry & 0x0F); // Get 4 right bits if (palentry == 0) //If the current pixel points to first colour in palette, { m_TileSetFile.Write8((uint)totaloffset, (byte)((m_TileSetFile.Read8((uint)totaloffset) & 0xF0) | swapped)); //point it to the swapped colour } if (palentry == (byte)swapped) //If the current pixel points to the swapped colour in palette, { m_TileSetFile.Write8((uint)totaloffset, (byte)((m_TileSetFile.Read8((uint)totaloffset) & 0xF0) | 0)); //point it to the first colour } } else { // Left 4 bits palentry = m_TileSetFile.Read8((uint)totaloffset); //Offset of current pixel's entry in palette file palentry = (byte)(palentry >> 4); if (palentry == 0) //If the current pixel points to first colour in palette, { m_TileSetFile.Write8((uint)totaloffset, (byte)((swapped << 4) | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F))); //point it to the swapped colour } if (palentry == (byte)swapped) //If the current pixel points to the swapped colour in palette, { m_TileSetFile.Write8((uint)totaloffset, (byte)(0 | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F))); //point it to the first colour } } } } } tileoffset += 2; if (!m_IsUsingTileMap) { tilenum++; } } } if (chkNCGDcmp.Checked) { m_TileSetFile.ForceCompression(); } m_TileSetFile.SaveChanges(); RedrawMinimap(m_IsUsingTileMap, m_SizeX, m_SizeY, m_BPP, m_PaletteRow); }
public void ImportBMP(string filename, int bpp, int sizeX, int sizeY, bool replaceMinimap = false, int numTilesX = 0, int numTilesY = 0, byte[] tilePaletteRows = null) { // The tile maps (NSC / ISC) files for minimaps are always arranged a particular way - 0, 1, 2...15, 32 for 128 x 128 Bitmap bmp = new Bitmap(filename); Color[] palette = bmp.Palette.Entries.ToArray <Color>(); if (palette.Length > 256) { MessageBox.Show("Too many colours\n\nYou must import an indexed bitmap with a maximum of 256 colours."); return; } // Write new palette m_PalFile = Program.m_ROM.GetFileFromName(txtSelNCL.Text); m_PalFile.Clear(); for (int i = 0; i < palette.Length; i++) { // Colour in BGR15 format (16 bits) written to every even address 0,2,4... m_PalFile.Write16((uint)i * 2, (ushort)(Helper.ColorToBGR15(palette[i]))); } // Pad the palette to a multiple of 16 colours byte nColourSlots = (byte)((palette.Length % 16 != 0) ? ((palette.Length + 16) & ~15) : palette.Length); for (int i = palette.Length; i < nColourSlots; i++) { m_PalFile.Write16((uint)i * 2, 0); } m_PalFile.SaveChanges(); // Fill current tmapfiles to use full mapsize x mapsize if (m_IsUsingTileMap) { m_TileMapFile = Program.m_ROM.GetFileFromName(txtSelNSC.Text); m_TileMapFile.Clear(); sizeX = bmp.Width; sizeY = bmp.Height; uint addr = 0; int curTile = 0; int row = (int)(sizeX / 8); for (int my = 0; my < sizeY; my += 8) { for (int mx = 0; mx < sizeX; mx += 8) { m_TileMapFile.Write16(addr, (ushort)curTile); curTile++; addr += 2; } } if (chkNSCDcmp.Checked) { m_TileMapFile.ForceCompression(); } m_TileMapFile.SaveChanges(); }// End If usingTMap //Check to see if there's already an identical tile and if so, change the current value to that //Works, but not if you want to keep existing data eg. multiple maps //List<List<byte>> tiles = new List<List<byte>>(); //List<byte> curTilePal = new List<byte>(); //uint tileoffset = 0; //for (int my = 0; my < sizeY; my += 8) //{ // for (int mx = 0; mx < sizeX; mx += 8) // { // ushort tilecrap = tmapfile.Read16(tileoffset); // uint tilenum = (uint)(tilecrap & 0x03FF); // curTilePal = new List<byte>(); // for (int ty = 0; ty < 8; ty++) // { // for (int tx = 0; tx < 8; tx++) // { // uint totaloffset = (uint)(tilenum * 64 + ty * 8 + tx);//Position of current pixel's entry // curTilePal.Add((byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty)))); // } // } // tiles.Add(curTilePal); // if (posInList(tiles, curTilePal) != -1) // { // tmapfile.Write16(tileoffset, (ushort)(posInList(tiles, curTilePal))); // } // tileoffset += 2; // } //} //Write the new image to file m_TileSetFile = Program.m_ROM.GetFileFromName(txtSelNCG.Text); m_TileSetFile.Clear(); uint tileoffset = 0; uint tileNum = 0; for (int my = 0; my < sizeY; my += 8) { for (int mx = 0; mx < sizeX; mx += 8) { for (int ty = 0; ty < 8; ty++) { for (int tx = 0; tx < 8; tx++) { if (bpp == 8) { uint totaloffset = (uint)(tileNum * 64 + ty * 8 + tx);//Position of current pixel's entry byte palentry = (byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty))); m_TileSetFile.Write8(totaloffset, (byte)(palentry)); } else if (bpp == 4) { float totaloffset = (float)((float)(tileNum * 64 + ty * 8 + tx) / 2f);//Address of current pixel byte palentry = (byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty))); int currentTileIndex = (int)tileNum; byte currentTileRowIndex = tilePaletteRows[currentTileIndex]; byte rowStartColourOffset = (byte)(16 * currentTileRowIndex); byte rowEndColourOffset = (byte)(16 * (currentTileRowIndex + 1) - 1); if (palentry < rowStartColourOffset || palentry > rowEndColourOffset) // Referencing colour outisde its row { Color referencedColour = Helper.BGR15ToColor(m_PalFile.Read16((uint)(palentry * 2))); // Find the same colour in the correct row and set the current pixel to reference that instead for (int col = rowStartColourOffset; col < rowEndColourOffset; col++) { uint offset = (uint)(col * 2); if (offset >= m_PalFile.m_Data.Length) { break; } Color currentColour = Helper.BGR15ToColor(m_PalFile.Read16(offset)); if (currentColour.Equals(referencedColour)) { palentry = (byte)col; break; } } } if (totaloffset % 1 == 0) { // Right 4 bits m_TileSetFile.Write8((uint)totaloffset, (byte)palentry); //(byte)((tsetfile.Read8((uint)totaloffset) & 0xF0) | palentry)); } else { // Left 4 bits m_TileSetFile.Write8((uint)totaloffset, (byte)((palentry << 4) | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F))); } } } } tileoffset += 2; tileNum++; } } if (chkNCGDcmp.Checked) { m_TileSetFile.ForceCompression(); } m_TileSetFile.SaveChanges(); // If it's a minimap that's being replaced, fill the tile maps to allow for multiple maps // and ensure the image's displayed at the right size since minimap sizes are hard-coded, // they are not based on the size of the imported image. if (replaceMinimap) { try { if (chk128.Checked) { FillMinimapTiles(128); } else if (chk256.Checked) { FillMinimapTiles(256); } } catch (Exception ex) { MessageBox.Show(ex.Message + ex.Source + ex.StackTrace); } } m_SizeX = sizeX; m_SizeY = sizeY; }
public void ImportBMP(string filename, int bpp, int sizeX, int sizeY, bool replaceMinimap = false, int numTilesX = 0, int numTilesY = 0, byte[] tilePaletteRows = null) { // The tile maps (NSC / ISC) files for minimaps are always arranged a particular way - 0, 1, 2...15, 32 for 128 x 128 Bitmap bmp = new Bitmap(filename); Color[] palette = bmp.Palette.Entries.ToArray<Color>(); if (palette.Length > 256) { MessageBox.Show("Too many colours\n\n" + "You must import an indexed bitmap with 256 colours or fewer."); return; } //Write new palette m_PalFile = Program.m_ROM.GetFileFromName(txtSelNCL.Text); m_PalFile.Clear(); for (int i = 0; i < palette.Length; i++) { //Colour in BGR15 format (16 bits) written to every even address 0,2,4... m_PalFile.Write16((uint)i * 2, (ushort)(Helper.ColorToBGR15(palette[i]))); } for (int i = palette.Length; i < 256; i++) m_PalFile.Write16((uint)i * 2, 0); m_PalFile.SaveChanges(); // Fill current tmapfiles to use full mapsize x mapsize if (m_IsUsingTileMap) { m_TileMapFile = Program.m_ROM.GetFileFromName(txtSelNSC.Text); m_TileMapFile.Clear(); sizeX = bmp.Width; sizeY = bmp.Height; uint addr = 0; int curTile = 0; int row = (int)(sizeX / 8); for (int my = 0; my < sizeY; my += 8) { for (int mx = 0; mx < sizeX; mx += 8) { m_TileMapFile.Write16(addr, (ushort)curTile); curTile++; addr += 2; } } if (chkNSCDcmp.Checked) m_TileMapFile.ForceCompression(); m_TileMapFile.SaveChanges(); }// End If usingTMap //Check to see if there's already an identical tile and if so, change the current value to that //Works, but not if you want to keep existing data eg. multiple maps //List<List<byte>> tiles = new List<List<byte>>(); //List<byte> curTilePal = new List<byte>(); //uint tileoffset = 0; //for (int my = 0; my < sizeY; my += 8) //{ // for (int mx = 0; mx < sizeX; mx += 8) // { // ushort tilecrap = tmapfile.Read16(tileoffset); // uint tilenum = (uint)(tilecrap & 0x03FF); // curTilePal = new List<byte>(); // for (int ty = 0; ty < 8; ty++) // { // for (int tx = 0; tx < 8; tx++) // { // uint totaloffset = (uint)(tilenum * 64 + ty * 8 + tx);//Position of current pixel's entry // curTilePal.Add((byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty)))); // } // } // tiles.Add(curTilePal); // if (posInList(tiles, curTilePal) != -1) // { // tmapfile.Write16(tileoffset, (ushort)(posInList(tiles, curTilePal))); // } // tileoffset += 2; // } //} //Write the new image to file m_TileSetFile = Program.m_ROM.GetFileFromName(txtSelNCG.Text); m_TileSetFile.Clear(); uint tileoffset = 0; uint tileNum = 0; for (int my = 0; my < sizeY; my += 8) { for (int mx = 0; mx < sizeX; mx += 8) { for (int ty = 0; ty < 8; ty++) { for (int tx = 0; tx < 8; tx++) { if (bpp == 8) { uint totaloffset = (uint)(tileNum * 64 + ty * 8 + tx);//Position of current pixel's entry byte palentry = (byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty))); m_TileSetFile.Write8(totaloffset, (byte)(palentry)); } else if (bpp == 4) { float totaloffset = (float)((float)(tileNum * 64 + ty * 8 + tx) / 2f);//Address of current pixel byte palentry = (byte)(Array.IndexOf(palette, bmp.GetPixel(mx + tx, my + ty))); int currentTileIndex = (int)tileNum; byte currentTileRowIndex = tilePaletteRows[currentTileIndex]; byte rowStartColourOffset = (byte)(16 * currentTileRowIndex); byte rowEndColourOffset = (byte)(16 * (currentTileRowIndex + 1) - 1); if (palentry < rowStartColourOffset || palentry > rowEndColourOffset) // Referencing colour outisde its row { Color referencedColour = Helper.BGR15ToColor(m_PalFile.Read16((uint)(palentry * 2))); // Find the same colour in the correct row and set the current pixel to reference that instead for (int col = rowStartColourOffset; col < rowEndColourOffset; col++) { uint offset = (uint)(col * 2); if (offset >= m_PalFile.m_Data.Length) break; Color currentColour = Helper.BGR15ToColor(m_PalFile.Read16(offset)); if (currentColour.Equals(referencedColour)) { palentry = (byte)col; break; } } } if (totaloffset % 1 == 0) { // Right 4 bits m_TileSetFile.Write8((uint)totaloffset, (byte)palentry); //(byte)((tsetfile.Read8((uint)totaloffset) & 0xF0) | palentry)); } else { // Left 4 bits m_TileSetFile.Write8((uint)totaloffset, (byte)((palentry << 4) | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F))); } } } } tileoffset += 2; tileNum++; } } if (chkNCGDcmp.Checked) m_TileSetFile.ForceCompression(); m_TileSetFile.SaveChanges(); // If it's a minimap that's being replaced, fill the tile maps to allow for multiple maps // and ensure the image's displayed at the right size as you can't change the size of // a level's minimap - it seems to be hardcoded somewhere (in level header?) if (replaceMinimap) { try { if (chk128.Checked) FillMinimapTiles(128); else if (chk256.Checked) FillMinimapTiles(256); } catch (Exception ex) { MessageBox.Show(ex.Message + ex.Source + ex.StackTrace); } } }
public void SwitchBackground(int swapped) { m_PalFile = Program.m_ROM.GetFileFromName(txtSelNCL.Text); //The background colour is the first colour stored in the palette ushort first = m_PalFile.Read16((uint)0);//Read the first colour in the palette file ushort swappedColour = m_PalFile.Read16((uint)(swapped * 2));//Read the colour to be swapped //Colour in BGR15 format (16 bits) written to every even address 0,2,4... m_PalFile.Write16((uint)0, swappedColour);//Write new background colour to first entry m_PalFile.Write16((uint)(swapped * 2), first);//Write the previously first colour to the colour being swapped m_PalFile.SaveChanges(); //Swap all palette file entries for the swapped colours in the graphic file m_TileSetFile = Program.m_ROM.GetFileFromName(txtSelNCG.Text); if (chkNCGDcmp.Checked) m_TileSetFile.ForceDecompression(); uint tileoffset = 0, tilenum = 0; ushort tilecrap = 0; for (int my = 0; my < m_SizeY; my += 8) { for (int mx = 0; mx < m_SizeX; mx += 8) { if (m_IsUsingTileMap) { tilecrap = m_TileMapFile.Read16(tileoffset); tilenum = (uint)(tilecrap & 0x03FF); } for (int ty = 0; ty < 8; ty++) { for (int tx = 0; tx < 8; tx++) { if (m_BPP == 8) { uint totaloffset = (uint)(tilenum * 64 + ty * 8 + tx);//Position of current pixel's entry byte palentry = m_TileSetFile.Read8(totaloffset); if (palentry == 0)//If the current pixel points to first colour in palette, m_TileSetFile.Write8(totaloffset, (byte)(swapped));//point it to the swapped colour if (palentry == (byte)swapped)//If the current pixel points to the swapped colour in palette, m_TileSetFile.Write8(totaloffset, (byte)0);//point it to the first colour } else if (m_BPP == 4) { float totaloffset = (float)((float)(tilenum * 64 + ty * 8 + tx) / 2f);//Address of current pixel byte palentry = 0; if (totaloffset % 1 == 0) { // Right 4 bits palentry = m_TileSetFile.Read8((uint)totaloffset);//Offset of current pixel's entry in palette file palentry = (byte)(palentry & 0x0F);// Get 4 right bits if (palentry == 0)//If the current pixel points to first colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)((m_TileSetFile.Read8((uint)totaloffset) & 0xF0) | swapped));//point it to the swapped colour if (palentry == (byte)swapped)//If the current pixel points to the swapped colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)((m_TileSetFile.Read8((uint)totaloffset) & 0xF0) | 0));//point it to the first colour } else { // Left 4 bits palentry = m_TileSetFile.Read8((uint)totaloffset);//Offset of current pixel's entry in palette file palentry = (byte)(palentry >> 4); if (palentry == 0)//If the current pixel points to first colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)((swapped << 4) | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F)));//point it to the swapped colour if (palentry == (byte)swapped)//If the current pixel points to the swapped colour in palette, m_TileSetFile.Write8((uint)totaloffset, (byte)(0 | (m_TileSetFile.Read8((uint)totaloffset) & 0x0F)));//point it to the first colour } } } } tileoffset += 2; if (!m_IsUsingTileMap) tilenum++; } } if (chkNCGDcmp.Checked) m_TileSetFile.ForceCompression(); m_TileSetFile.SaveChanges(); RedrawMinimap(m_IsUsingTileMap, m_SizeX, m_SizeY, m_BPP, m_PaletteRow); }
public void ApplyPatch(NitroROM rom) { Program.m_ROM.BeginRW(); List <AddressDataPair> addressDataPairs = null; switch (rom.m_Version) { case NitroROM.Version.EUR: addressDataPairs = m_EURPatch; m_EURRestoreData = GenerateRestoreData(m_EURPatch); break; case NitroROM.Version.USA_v1: addressDataPairs = m_USv1Patch; m_USv1RestoreData = GenerateRestoreData(m_USv1Patch); break; case NitroROM.Version.USA_v2: addressDataPairs = m_USv2Patch; m_USv2RestoreData = GenerateRestoreData(m_USv2Patch); break; case NitroROM.Version.JAP: addressDataPairs = m_JAPPatch; m_JAPRestoreData = GenerateRestoreData(m_JAPPatch); break; } if (m_DecompressAllOverlays) { Helper.DecompressOverlaysWithinGame(); } if (m_FileToPatch != null) { NitroFile myFile = Program.m_ROM.GetFileFromName(m_FileToPatch); foreach (AddressDataPair addressDataPair in addressDataPairs) { for (int i = 0; i < addressDataPair.m_Data.Length; i++) { myFile.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } Program.m_ROM.EndRW(); myFile.SaveChanges(); return; } INitroROMBlock fileToPatch = null; if (m_FileToPatch != null) { fileToPatch = Program.m_ROM.GetFileFromName(m_FileToPatch); } else if (m_OverlayID != null) { fileToPatch = new NitroOverlay(Program.m_ROM, uint.Parse(m_OverlayID)); } foreach (AddressDataPair addressDataPair in addressDataPairs) { for (int i = 0; i < addressDataPair.m_Data.Length; i++) { if (fileToPatch == null) { if (Program.m_IsROMFolder) { Program.m_ROM.arm9W.BaseStream.Position = addressDataPair.m_Address + (uint)i - Program.m_ROM.headerSize; Program.m_ROM.arm9W.Write(addressDataPair.m_Data[i]); } else { rom.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } else { fileToPatch.Write8(addressDataPair.m_Address + (uint)i, addressDataPair.m_Data[i]); } } } Program.m_ROM.EndRW(); if (fileToPatch != null) { fileToPatch.SaveChanges(); } }