private void btnDecompressOverlay_Click(object sender, EventArgs e) { uint ovlID = uint.Parse(m_SelectedOverlay.Substring(8)); NitroOverlay ovl = new NitroOverlay(Program.m_ROM, ovlID); ovl.SaveChanges(); }
public void SaveChanges() { //using a MemoryStream instead of an INitroROMBlock for dynamic size MemoryStream stream = new MemoryStream(); BinaryWriter binWriter = new BinaryWriter(stream); byte overlayInitialiserVersion = 0; switch (Program.m_ROM.m_Version) { case NitroROM.Version.EUR: binWriter.Write(Properties.Resources.level_ovl_init_EUR_001); overlayInitialiserVersion = 1; break; case NitroROM.Version.USA_v1: binWriter.Write(Properties.Resources.level_ovl_init_USAv1); break; case NitroROM.Version.USA_v2: binWriter.Write(Properties.Resources.level_ovl_init_USAv2); break; case NitroROM.Version.JAP: binWriter.Write(Properties.Resources.level_ovl_init_JAP); break; default: throw new InvalidDataException("This ROM is an unknown version."); } m_LevelSettings.LevelFormatVersion = k_LevelFormatVersion; m_LevelSettings.OverlayInitialiserVersion = overlayInitialiserVersion; uint areaTableOffset; m_LevelSettings.SaveChanges(binWriter); SaveCLPS(binWriter); SaveMiscObjs(binWriter); SaveRegularObjs(binWriter, out areaTableOffset); LevelTexAnim.SaveAll(binWriter, m_TexAnims, areaTableOffset, (uint)m_NumAreas); if (DoesLevelSupportDynamicLibs()) { while (stream.Position % 2 != 0) { binWriter.Write((byte)0); } Helper.WritePosAndRestore(binWriter, 0x30, 0); binWriter.Write((ushort)m_DynLibIDs.Count); m_DynLibIDs.ForEach(x => binWriter.Write((ushort)x)); Helper.AlignWriter(binWriter, 4); } Array.Clear(m_Overlay.m_Data, 0, m_Overlay.m_Data.Length); Array.Resize(ref m_Overlay.m_Data, (int)stream.Length); stream.Position = 0; new BinaryReader(stream).Read(m_Overlay.m_Data, 0, (int)stream.Length); m_Overlay.SaveChanges(); }
public static void DecompressOverlaysWithinGame() { if (CheckAllOverlaysDecompressed()) { return; } for (int i = 0; i < 155; i++) { NitroOverlay overlay = new NitroOverlay(Program.m_ROM, (uint)i); // Overlay is decompressed when initialised above automatically if needed, just need to save changes overlay.SaveChanges(); } }
private void btnReplaceOverlay_Click(object sender, EventArgs e) { if (m_SelectedOverlay == null) { return; } OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.Cancel) { return; } uint ovlID = uint.Parse(m_SelectedOverlay.Substring(8)); NitroOverlay ovl = new NitroOverlay(Program.m_ROM, ovlID); ovl.Clear(); ovl.WriteBlock(0, System.IO.File.ReadAllBytes(ofd.FileName)); ovl.SaveChanges(); }
private void Patch_v4(BackgroundWorker lazyman) { uint lvl_start = 0; // Music table address uint music_tbl_addr = 0; // Store locations of the music bytes (music table address, +1, +2) - update to point to within overlay uint music_tbl_byte_1_addr = 0, music_tbl_byte_2_addr = 0, music_tbl_byte_3_addr = 0; // Locations at which offsets into the music table are calculated uint music_byte_1_offset = 0, music_byte_2_offset = 0, music_byte_3_offset = 0; switch (m_Version) { case Version.EUR: music_tbl_addr = 0x75768; music_byte_1_offset = 0x2de28; music_byte_2_offset = 0x2d184; music_byte_3_offset = 0x2d360; music_tbl_byte_1_addr = 0x2de60; music_tbl_byte_2_addr = 0x2d608; music_tbl_byte_3_addr = 0x2d644; lvl_start = 34925216; break; case Version.JAP: music_tbl_addr = 0x739d8; music_byte_1_offset = 0x2cd80; music_byte_2_offset = 0x2c32c; music_byte_3_offset = 0x2c508; music_tbl_byte_1_addr = 0x2cdb8; music_tbl_byte_2_addr = 0x2c7b0; music_tbl_byte_3_addr = 0x2c7ec; lvl_start = 34878592; break; case Version.USA_v1: music_tbl_addr = 0x73434; music_byte_1_offset = 0x2caa8; music_byte_2_offset = 0x2c058; music_byte_3_offset = 0x2c234; music_tbl_byte_1_addr = 0x2cae0; music_tbl_byte_2_addr = 0x2c4d8; music_tbl_byte_3_addr = 0x2c514; lvl_start = 34880416; break; case Version.USA_v2: music_tbl_addr = 0x74154; music_byte_1_offset = 0x2cdbc; music_byte_2_offset = 0x2c368; music_byte_3_offset = 0x2c544; music_tbl_byte_1_addr = 0x2cdf4; music_tbl_byte_2_addr = 0x2c7ec; music_tbl_byte_3_addr = 0x2c828; lvl_start = 34887456; break; } // Copy level music data for (int i = 0; i < 52; i++) { NitroOverlay ovl = new NitroOverlay(this, (uint)(103 + i)); m_FileStream.Position = music_tbl_addr + (i * 3); ovl.Write8(0x7C + 0, m_BinReader.ReadByte()); ovl.Write8(0x7C + 1, m_BinReader.ReadByte()); ovl.Write8(0x7C + 2, m_BinReader.ReadByte()); ovl.SaveChanges(); } // Patch music code to load from overlays m_FileStream.Position = music_byte_1_offset; // Offset into table generated m_BinWriter.Write((uint)0xe3a03000); //MOV R3, #0 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_1_addr; // Stores location of music table byte 1 m_BinWriter.Write((uint)(lvl_start + 0x7C)); // Write location in overlay of music data m_FileStream.Position = music_byte_2_offset; m_BinWriter.Write((uint)0xe3a02001); //MOV R2, #1 ;Set offset to 1 m_FileStream.Position = music_tbl_byte_2_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); m_FileStream.Position = music_byte_3_offset; m_BinWriter.Write((uint)0xe3a01002);//MOV R1, #2 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_3_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); lazyman.ReportProgress(499); }
private void Patch_v2(BackgroundWorker lazyman) { lazyman.ReportProgress(200); uint levelptr_table = 0, objbank_table = 0; uint mempatch1 = 0, mempatch2 = 0; byte[] loadercode = null; uint lvl_ovlid_table = 0; uint unload_patch = 0, unload_branchop = 0; uint[] ovltable_addr_patch = new uint[4]; uint[] ovltable_size_patch = new uint[4]; uint lvlload_addr_patch = 0, lvlload_code_patch = 0; uint objbank_addr_patch = 0, objbank_code_patch = 0; switch (m_Version) { case Version.EUR: levelptr_table = 0x92208; objbank_table = 0x75998; mempatch1 = 0x18B60; mempatch2 = 0x58DE0; loadercode = Properties.Resources.level_ovl_init_EUR; lvl_ovlid_table = 0x758C8; unload_patch = 0x2DE80; unload_branchop = ARM_BL(0x0202DE80, 0x0214EAD8); ovltable_addr_patch[0] = 0x17E90; ovltable_addr_patch[1] = 0x17F30; ovltable_addr_patch[2] = 0x17FCC; ovltable_addr_patch[3] = 0x180FC; ovltable_size_patch[0] = 0x17E80; ovltable_size_patch[1] = 0x17ED0; ovltable_size_patch[2] = 0x17F70; ovltable_size_patch[3] = 0x180C4; lvlload_addr_patch = 0x2D62C; lvlload_code_patch = 0x2D288; objbank_addr_patch = 0x2E074; objbank_code_patch = 0x2DFAC; break; case Version.JAP: levelptr_table = 0x902B8; objbank_table = 0x73C08; mempatch1 = 0x57368; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_JAP; lvl_ovlid_table = 0x73B38; unload_patch = 0x2CDD8; unload_branchop = ARM_BL(0x0202CDD8, 0x021434B8); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C7D4; lvlload_code_patch = 0x2C430; objbank_addr_patch = 0x2CFCC; objbank_code_patch = 0x2CF04; break; case Version.USA_v1: levelptr_table = 0x8FDB0; objbank_table = 0x73664; mempatch1 = 0x56EB8; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_USAv1; lvl_ovlid_table = 0x73594; unload_patch = 0x2CB00; unload_branchop = ARM_BL(0x0202CB00, 0x02143BD8); ovltable_addr_patch[0] = 0x17D70; ovltable_addr_patch[1] = 0x17E10; ovltable_addr_patch[2] = 0x17EAC; ovltable_addr_patch[3] = 0x17FDC; ovltable_size_patch[0] = 0x17D60; ovltable_size_patch[1] = 0x17DB0; ovltable_size_patch[2] = 0x17E50; ovltable_size_patch[3] = 0x17FA4; lvlload_addr_patch = 0x2C4FC; lvlload_code_patch = 0x2C15C; objbank_addr_patch = 0x2CCF4; objbank_code_patch = 0x2CC2C; break; case Version.USA_v2: levelptr_table = 0x90ACC; objbank_table = 0x74384; mempatch1 = 0x18A44; mempatch2 = 0x57B30; loadercode = Properties.Resources.level_ovl_init_USAv2; lvl_ovlid_table = 0x742B4; unload_patch = 0x2CE14; unload_branchop = ARM_BL(0x0202CE14, 0x02145758); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C810; lvlload_code_patch = 0x2C46C; objbank_addr_patch = 0x2D008; objbank_code_patch = 0x2CF40; break; } // tweak the root heap start address to gain more overlay space :) m_FileStream.Position = mempatch1; uint lvl_start = m_BinReader.ReadUInt32(); uint lvl_end = lvl_start + LEVEL_OVERLAY_SIZE; m_FileStream.Position = mempatch1; m_BinWriter.Write(lvl_end); if (mempatch2 != 0xFFFFFFFF) { m_FileStream.Position = mempatch2; m_BinWriter.Write(lvl_end); } // patch level overlay unloading m_FileStream.Position = unload_patch; m_BinWriter.Write(unload_branchop); // patch more stuff foreach (uint addr in ovltable_addr_patch) { m_FileStream.Position = addr; m_BinWriter.Write((uint)(0x02000000 + levelptr_table)); } foreach (uint addr in ovltable_size_patch) { m_FileStream.Position = addr; uint op = m_BinReader.ReadUInt32(); op = (op & 0xFFFFFF00) | 0x0D; m_FileStream.Position = addr; m_BinWriter.Write(op); } lazyman.ReportProgress(201); // for each level, create a new overlay with the loader code and level data uint dataoffset = (uint)((loadercode.Length + 3) & ~3); for (int i = 0; i < 52; i++) { uint overlayid = AddOverlay(lvl_start); m_FileStream.Position = lvl_ovlid_table + (i * 4); uint old_overlayid = m_BinReader.ReadUInt32(); m_FileStream.Position = lvl_ovlid_table + (i * 4); m_BinWriter.Write(overlayid); NitroOverlay ovl = new NitroOverlay(this, overlayid); ovl.SetInitializer(lvl_start, 4); ovl.WriteBlock(0, loadercode); // write the object bank settings m_FileStream.Position = objbank_table + (i * 7); byte[] objbanks = m_BinReader.ReadBytes(7); ovl.WriteBlock(dataoffset, objbanks); ovl.Write8(dataoffset + 0x7, 0x00); ovl.Write32(dataoffset + 0x8, (uint)(i + 1)); // copy level data { NitroOverlay oldovl = new NitroOverlay(this, old_overlayid); uint oldbase = oldovl.GetRAMAddr(); m_FileStream.Position = levelptr_table + (i * 4); uint header_offset = m_BinReader.ReadUInt32() - oldbase; uint curoffset = dataoffset + 0x40; // CLPS (collision behaviors) chunk { uint clps_addr = oldovl.ReadPointer(header_offset); ushort clps_num = oldovl.Read16(clps_addr + 0x06); uint clps_size = (uint)(8 + (clps_num * 8)); byte[] clps = oldovl.ReadBlock(clps_addr, clps_size); ovl.WriteBlock(curoffset, clps); ovl.WritePointer(dataoffset + 0x0C, curoffset); curoffset += clps_size; } // misc objects table list { uint tables_addr = oldovl.ReadPointer(header_offset + 0x4); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.WritePointer(dataoffset + 0x10, curoffset); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) { throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); } int[] datasizes = { 16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4 }; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } // main object table lists // and that stuff about texture scrolling { uint tlists_addr = oldovl.ReadPointer(header_offset + 0x10); byte tlists_num = oldovl.Read8(header_offset + 0x14); uint tlists_new_addr = curoffset; curoffset += (uint)(tlists_num * 12); ovl.WritePointer(dataoffset + 0x1C, tlists_new_addr); ovl.Write8(dataoffset + 0x20, tlists_num); for (byte tl = 0; tl < tlists_num; tl++) { uint tables_addr = oldovl.ReadPointer(tlists_addr); uint texanm_addr = oldovl.ReadPointer(tlists_addr + 0x4); if (tables_addr != 0xFFFFFFFF) { ovl.WritePointer(tlists_new_addr, curoffset); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) { throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); } int[] datasizes = { 16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4 }; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } else { ovl.Write32(tlists_new_addr, 0); } if (texanm_addr != 0xFFFFFFFF)//If not null { ovl.WritePointer(tlists_new_addr + 0x4, curoffset); uint texanm_new_addr = curoffset; curoffset += 0x18; uint textures_addr = oldovl.ReadPointer(texanm_addr + 0x14); uint numscale = 0, numrot = 0, numtrans = 0; uint numtextures = oldovl.Read32(texanm_addr + 0x10); ovl.Write32(texanm_new_addr, oldovl.Read32(texanm_addr)); ovl.Write32(texanm_new_addr + 0x10, numtextures); uint textures_new_addr = curoffset; curoffset += (numtextures * 0x1C); ovl.WritePointer(texanm_new_addr + 0x14, textures_new_addr); for (uint t = 0; t < numtextures; t++) { uint tex_old_addr = textures_addr + (t * 0x1C); uint tex_new_addr = textures_new_addr + (t * 0x1C); ushort tex_scalenum = oldovl.Read16(tex_old_addr + 0x0C); ushort tex_scalestart = oldovl.Read16(tex_old_addr + 0x0E); ushort tex_rotnum = oldovl.Read16(tex_old_addr + 0x10); ushort tex_rotstart = oldovl.Read16(tex_old_addr + 0x12); ushort tex_transnum = oldovl.Read16(tex_old_addr + 0x14); ushort tex_transstart = oldovl.Read16(tex_old_addr + 0x16); if ((tex_scalestart + tex_scalenum) > numscale) { numscale = (uint)(tex_scalestart + tex_scalenum); } if ((tex_rotstart + tex_rotnum) > numrot) { numrot = (uint)(tex_rotstart + tex_rotnum); } if ((tex_transstart + tex_transnum) > numtrans) { numtrans = (uint)(tex_transstart + tex_transnum); } ovl.Write32(tex_new_addr, oldovl.Read32(tex_old_addr)); ovl.WritePointer(tex_new_addr + 0x4, curoffset); ovl.Write32(tex_new_addr + 0x8, oldovl.Read32(tex_old_addr + 0x8)); ovl.Write16(tex_new_addr + 0xC, tex_scalenum); ovl.Write16(tex_new_addr + 0xE, tex_scalestart); ovl.Write16(tex_new_addr + 0x10, tex_rotnum); ovl.Write16(tex_new_addr + 0x12, tex_rotstart); ovl.Write16(tex_new_addr + 0x14, tex_transnum); ovl.Write16(tex_new_addr + 0x16, tex_transstart); ovl.Write32(tex_new_addr + 0x18, oldovl.Read32(tex_old_addr + 0x18)); string tex_matname = oldovl.ReadString(oldovl.ReadPointer(tex_old_addr + 0x4), 0); ovl.WriteString(curoffset, tex_matname, 0); curoffset += (uint)((tex_matname.Length + 3) & ~3); } uint scale_addr = oldovl.ReadPointer(texanm_addr + 0x4); ovl.WritePointer(texanm_new_addr + 0x4, curoffset); for (uint v = 0; v < numscale; v++) { ovl.Write32(curoffset, oldovl.Read32(scale_addr + (v * 4))); curoffset += 4; } uint rot_addr = oldovl.ReadPointer(texanm_addr + 0x8); ovl.WritePointer(texanm_new_addr + 0x8, curoffset); for (uint v = 0; v < numrot; v++) { ovl.Write16(curoffset, oldovl.Read16(rot_addr + (v * 2))); curoffset += 2; } curoffset = (uint)((curoffset + 3) & ~3); uint trans_addr = oldovl.ReadPointer(texanm_addr + 0xC); ovl.WritePointer(texanm_new_addr + 0xC, curoffset); for (uint v = 0; v < numtrans; v++) { ovl.Write32(curoffset, oldovl.Read32(trans_addr + (v * 4))); curoffset += 4; } } else { ovl.Write32(tlists_new_addr + 0x4, 0); } ovl.Write32(tlists_new_addr + 0x8, oldovl.Read32(tlists_addr + 0x8)); tlists_new_addr += 12; tlists_addr += 12; } } // misc header pieces ovl.Write32(dataoffset + 0x14, oldovl.Read32(header_offset + 0x8)); ovl.Write32(dataoffset + 0x18, oldovl.Read32(header_offset + 0xC)); ovl.Write16(dataoffset + 0x22, oldovl.Read16(header_offset + 0x16)); ovl.Write8(dataoffset + 0x24, oldovl.Read8(header_offset + 0x18)); } ovl.SaveChanges(); lazyman.ReportProgress(201 + (int)((98f / 54f) * i)); } // fix the level loader as to load from the new overlays m_FileStream.Position = lvlload_addr_patch; m_BinWriter.Write((uint)(lvl_start + dataoffset + 0xC)); m_FileStream.Position = lvlload_code_patch; m_BinWriter.Write((uint)0xE1A00000); // refill the old level header address table // to adapt it to its new usages m_FileStream.Position = levelptr_table; for (uint i = 0; i < 13; i++) { m_BinWriter.Write((uint)0xFFFFFFFF); m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); } m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); // fix the object banks thingy m_FileStream.Position = objbank_addr_patch; m_BinWriter.Write((uint)(levelptr_table + 0x0200009C)); m_FileStream.Position = objbank_code_patch; m_BinWriter.Write((uint)0xE1A07001); // phew! what a goddamn long thing lazyman.ReportProgress(299); }
private void dLPatchToolStripMenuItem_Click(object sender, EventArgs e) { if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR roms only!"); } else { bool autorw = Program.m_ROM.CanRW(); if (!autorw) { Program.m_ROM.BeginRW(); } if (Program.m_ROM.Read32(0x6590) != 0) //the patch makes this not 0 { if (!autorw) { Program.m_ROM.EndRW(); } MessageBox.Show("Rom has already been patched!"); return; } if (!autorw) { Program.m_ROM.EndRW(); } if (MessageBox.Show("This will patch the ROM. " + "Continue with the patch?", "Table Shifting Patch", MessageBoxButtons.YesNo) == DialogResult.No) { return; } if (!autorw) { Program.m_ROM.BeginRW(); } NitroOverlay ov2 = new NitroOverlay(Program.m_ROM, 2); //Move the ACTOR_SPAWN_TABLE so it can expand Program.m_ROM.WriteBlock(0x6590, Program.m_ROM.ReadBlock(0x90864, 0x61c)); Program.m_ROM.WriteBlock(0x90864, new byte[0x61c]); //Adjust pointers Program.m_ROM.Write32(0x1a198, 0x02006590); //Move the OBJ_TO_ACTOR_TABLE so it can expand Program.m_ROM.WriteBlock(0x4b00, ov2.ReadBlock(0x0210cbf4 - ov2.GetRAMAddr(), 0x28c)); ov2.WriteBlock(0x0210cbf4 - ov2.GetRAMAddr(), new byte[0x28c]); //Adjust pointers ov2.Write32(0x020fe890 - ov2.GetRAMAddr(), 0x02004b00); ov2.Write32(0x020fe958 - ov2.GetRAMAddr(), 0x02004b00); ov2.Write32(0x020fea44 - ov2.GetRAMAddr(), 0x02004b00); //Add the dynamic library loading and cleanup code Program.m_ROM.WriteBlock(0x90864, Properties.Resources.dynamic_library_loader); //Add the hooks (by replacing LoadObjBankOverlays()) Program.m_ROM.WriteBlock(0x2df70, Properties.Resources.static_overlay_loader); if (!autorw) { Program.m_ROM.EndRW(); } ov2.SaveChanges(); } }
private void importPatchToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog o = new OpenFileDialog(); o.Filter = "SM64DSe Patch|*.sp"; o.RestoreDirectory = true; if (o.ShowDialog() == DialogResult.OK) { //Each line. var s = File.ReadAllLines(o.FileName); string basePath = Path.GetDirectoryName(o.FileName) + "/"; foreach (var l in s) { //Get parameters. string t = l; if (t.Contains("#")) { t = t.Substring(0, t.IndexOf('#')); } var p = t.Split(' '); if (p.Length == 0) { continue; } //Switch command. switch (p[0].ToLower()) { //Replace file. case "replace": if (ushort.TryParse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture, out _)) { Program.m_ROM.ReinsertFile(Program.m_ROM.GetFileIDFromInternalID(ushort.Parse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture)), File.ReadAllBytes(basePath + p[2])); } else { Program.m_ROM.ReinsertFile(Program.m_ROM.GetFileIDFromName(p[1]), File.ReadAllBytes(basePath + p[2])); } break; //Replace ARM9. case "replace_arm9": var r = Program.m_ROM; r.BeginRW(true); uint arm9addr = r.Read32(0x20); uint arm9size = r.Read32(0x2C); byte[] newArm9 = File.ReadAllBytes(basePath + p[1]); if (newArm9.Length > arm9size) { r.MakeRoom(arm9addr + arm9size, (uint)(newArm9.Length - arm9size)); r.AutoFix(0xFFFF, arm9addr + arm9size, (int)(newArm9.Length - arm9size)); } r.Write32(0x2C, (uint)newArm9.Length); r.WriteBlock(arm9addr, newArm9); r.EndRW(true); r.LoadROM(r.m_Path); break; //Replace overlay. case "replace_overlay": NitroOverlay n2 = new NitroOverlay(Program.m_ROM, uint.Parse(p[1])); n2.m_Data = File.ReadAllBytes(basePath + p[2]); n2.SaveChanges(); break; //Rename file. case "rename": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } Program.m_ROM.StartFilesystemEdit(); ushort fileIdFromName; if (ushort.TryParse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture, out _)) { fileIdFromName = Program.m_ROM.GetFileIDFromInternalID(ushort.Parse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture)); } else { fileIdFromName = Program.m_ROM.GetFileIDFromName(p[1]); } string filename = Program.m_ROM.m_FileEntries[fileIdFromName].FullName; string newName = p[2]; int length = filename.LastIndexOf('/') + 1; string str1 = filename.Substring(0, length) + newName; Program.m_ROM.m_FileEntries[fileIdFromName].Name = newName; Program.m_ROM.m_FileEntries[fileIdFromName].FullName = str1; Program.m_ROM.SaveFilesystem(); this.tvFileList.Nodes.Clear(); ROMFileSelect.LoadFileList(this.tvFileList); this.tvARM9Overlays.Nodes.Clear(); ROMFileSelect.LoadOverlayList(this.tvARM9Overlays); break; //Import level XML. case "import_xml": Level lv = new Level(int.Parse(p[1])); try { LevelDataXML_Importer.ImportLevel(lv, basePath + p[2], true); } catch (InvalidDataException ex) { MessageBox.Show(ex.Message); } catch (Exception ex) { new ExceptionMessageBox("Error parsing level, changes have not been saved", ex).ShowDialog(); } Program.m_ROM.LoadROM(Program.m_ROM.m_Path); break; //Add overlay. case "add_overlay": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } OverlayEditor oe = new OverlayEditor(); oe.AddOverlay(oe.Overlays.Count); var ov = oe.Overlays[oe.Overlays.Count - 1]; var overlayFile = File.ReadAllBytes(basePath + p[6]); ov.ID = (uint)(oe.Overlays.Count - 1); ov.RAMAddress = uint.Parse(p[1], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.RAMSize = (uint)overlayFile.Length; ov.BSSSize = uint.Parse(p[4], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.StaticInitStart = uint.Parse(p[2], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.StaticInitEnd = uint.Parse(p[3], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov.Flags = uint.Parse(p[5], NumberStyles.HexNumber, CultureInfo.CurrentCulture); oe.Overlays[oe.Overlays.Count - 1] = ov; oe.saveChangesButton_Click(null, new EventArgs()); oe.closeButton_Click(null, new EventArgs()); NitroOverlay n = new NitroOverlay(Program.m_ROM, (uint)(oe.Overlays.Count - 1)); n.m_Data = overlayFile; n.SaveChanges(); this.tvFileList.Nodes.Clear(); ROMFileSelect.LoadFileList(this.tvFileList); this.tvARM9Overlays.Nodes.Clear(); ROMFileSelect.LoadOverlayList(this.tvARM9Overlays); break; //Edit overlay. case "edit_overlay": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } Program.m_ROM.StartFilesystemEdit(); var ov2 = Program.m_ROM.m_OverlayEntries[int.Parse(p[1])]; ov2.RAMAddress = uint.Parse(p[2], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.BSSSize = uint.Parse(p[5], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.StaticInitStart = uint.Parse(p[3], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.StaticInitEnd = uint.Parse(p[4], NumberStyles.HexNumber, CultureInfo.CurrentCulture); ov2.Flags = uint.Parse(p[6], NumberStyles.HexNumber, CultureInfo.CurrentCulture); Program.m_ROM.m_OverlayEntries[int.Parse(p[1])] = ov2; Program.m_ROM.SaveFilesystem(); break; //Delete overlay. case "delete_overlay": if (Program.m_ROM.m_Version != NitroROM.Version.EUR) { MessageBox.Show("This is for EUR ROMs only!"); continue; } OverlayEditor oe2 = new OverlayEditor(); oe2.DeleteOverlay(int.Parse(p[1])); oe2.saveChangesButton_Click(null, new EventArgs()); oe2.closeButton_Click(null, new EventArgs()); break; } } } }
private void Patch_v4(BackgroundWorker lazyman) { uint lvl_start = 0; // Music table address uint music_tbl_addr = 0; // Store locations of the music bytes (music table address, +1, +2) - update to point to within overlay uint music_tbl_byte_1_addr = 0, music_tbl_byte_2_addr = 0, music_tbl_byte_3_addr = 0; // Locations at which offsets into the music table are calculated uint music_byte_1_offset = 0, music_byte_2_offset = 0, music_byte_3_offset = 0; switch (m_Version) { case Version.EUR: music_tbl_addr = 0x75768; music_byte_1_offset = 0x2de28; music_byte_2_offset = 0x2d184; music_byte_3_offset = 0x2d360; music_tbl_byte_1_addr = 0x2de60; music_tbl_byte_2_addr = 0x2d608; music_tbl_byte_3_addr = 0x2d644; lvl_start = 34925216; break; case Version.JAP: music_tbl_addr = 0x739d8; music_byte_1_offset = 0x2cd80; music_byte_2_offset = 0x2c32c; music_byte_3_offset = 0x2c508; music_tbl_byte_1_addr = 0x2cdb8; music_tbl_byte_2_addr = 0x2c7b0; music_tbl_byte_3_addr = 0x2c7ec; lvl_start = 34878592; break; case Version.USA_v1: music_tbl_addr = 0x73434; music_byte_1_offset = 0x2caa8; music_byte_2_offset = 0x2c058; music_byte_3_offset = 0x2c234; music_tbl_byte_1_addr = 0x2cae0; music_tbl_byte_2_addr = 0x2c4d8; music_tbl_byte_3_addr = 0x2c514; lvl_start = 34880416; break; case Version.USA_v2: music_tbl_addr = 0x74154; music_byte_1_offset = 0x2cdbc; music_byte_2_offset = 0x2c368; music_byte_3_offset = 0x2c544; music_tbl_byte_1_addr = 0x2cdf4; music_tbl_byte_2_addr = 0x2c7ec; music_tbl_byte_3_addr = 0x2c828; lvl_start = 34887456; break; } // Copy level music data for (int i = 0; i < 52; i++) { NitroOverlay ovl = new NitroOverlay(this, (uint)(103 + i)); m_FileStream.Position = music_tbl_addr + (i * 3); ovl.Write8(0x7C + 0, m_BinReader.ReadByte()); ovl.Write8(0x7C + 1, m_BinReader.ReadByte()); ovl.Write8(0x7C + 2, m_BinReader.ReadByte()); ovl.SaveChanges(); } // Patch music code to load from overlays m_FileStream.Position = music_byte_1_offset;// Offset into table generated m_BinWriter.Write((uint)0xe3a03000);//MOV R3, #0 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_1_addr;// Stores location of music table byte 1 m_BinWriter.Write((uint)(lvl_start + 0x7C));// Write location in overlay of music data m_FileStream.Position = music_byte_2_offset; m_BinWriter.Write((uint)0xe3a02001);//MOV R2, #1 ;Set offset to 1 m_FileStream.Position = music_tbl_byte_2_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); m_FileStream.Position = music_byte_3_offset; m_BinWriter.Write((uint)0xe3a01002);//MOV R1, #2 ;Set offset to 0 m_FileStream.Position = music_tbl_byte_3_addr; m_BinWriter.Write((uint)(lvl_start + 0x7C)); lazyman.ReportProgress(499); }
private void Patch_v2(BackgroundWorker lazyman) { lazyman.ReportProgress(200); uint levelptr_table = 0, objbank_table = 0; uint mempatch1 = 0, mempatch2 = 0; byte[] loadercode = null; uint lvl_ovlid_table = 0; uint unload_patch = 0, unload_branchop = 0; uint[] ovltable_addr_patch = new uint[4]; uint[] ovltable_size_patch = new uint[4]; uint lvlload_addr_patch = 0, lvlload_code_patch = 0; uint objbank_addr_patch = 0, objbank_code_patch = 0; switch (m_Version) { case Version.EUR: levelptr_table = 0x92208; objbank_table = 0x75998; mempatch1 = 0x18B60; mempatch2 = 0x58DE0; loadercode = Properties.Resources.level_ovl_init_EUR; lvl_ovlid_table = 0x758C8; unload_patch = 0x2DE80; unload_branchop = ARM_BL(0x0202DE80, 0x0214EAD8); ovltable_addr_patch[0] = 0x17E90; ovltable_addr_patch[1] = 0x17F30; ovltable_addr_patch[2] = 0x17FCC; ovltable_addr_patch[3] = 0x180FC; ovltable_size_patch[0] = 0x17E80; ovltable_size_patch[1] = 0x17ED0; ovltable_size_patch[2] = 0x17F70; ovltable_size_patch[3] = 0x180C4; lvlload_addr_patch = 0x2D62C; lvlload_code_patch = 0x2D288; objbank_addr_patch = 0x2E074; objbank_code_patch = 0x2DFAC; break; case Version.JAP: levelptr_table = 0x902B8; objbank_table = 0x73C08; mempatch1 = 0x57368; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_JAP; lvl_ovlid_table = 0x73B38; unload_patch = 0x2CDD8; unload_branchop = ARM_BL(0x0202CDD8, 0x021434B8); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C7D4; lvlload_code_patch = 0x2C430; objbank_addr_patch = 0x2CFCC; objbank_code_patch = 0x2CF04; break; case Version.USA_v1: levelptr_table = 0x8FDB0; objbank_table = 0x73664; mempatch1 = 0x56EB8; mempatch2 = 0xFFFFFFFF; loadercode = Properties.Resources.level_ovl_init_USAv1; lvl_ovlid_table = 0x73594; unload_patch = 0x2CB00; unload_branchop = ARM_BL(0x0202CB00, 0x02143BD8); ovltable_addr_patch[0] = 0x17D70; ovltable_addr_patch[1] = 0x17E10; ovltable_addr_patch[2] = 0x17EAC; ovltable_addr_patch[3] = 0x17FDC; ovltable_size_patch[0] = 0x17D60; ovltable_size_patch[1] = 0x17DB0; ovltable_size_patch[2] = 0x17E50; ovltable_size_patch[3] = 0x17FA4; lvlload_addr_patch = 0x2C4FC; lvlload_code_patch = 0x2C15C; objbank_addr_patch = 0x2CCF4; objbank_code_patch = 0x2CC2C; break; case Version.USA_v2: levelptr_table = 0x90ACC; objbank_table = 0x74384; mempatch1 = 0x18A44; mempatch2 = 0x57B30; loadercode = Properties.Resources.level_ovl_init_USAv2; lvl_ovlid_table = 0x742B4; unload_patch = 0x2CE14; unload_branchop = ARM_BL(0x0202CE14, 0x02145758); ovltable_addr_patch[0] = 0x17DE4; ovltable_addr_patch[1] = 0x17E84; ovltable_addr_patch[2] = 0x17F20; ovltable_addr_patch[3] = 0x18050; ovltable_size_patch[0] = 0x17DD4; ovltable_size_patch[1] = 0x17E24; ovltable_size_patch[2] = 0x17EC4; ovltable_size_patch[3] = 0x18018; lvlload_addr_patch = 0x2C810; lvlload_code_patch = 0x2C46C; objbank_addr_patch = 0x2D008; objbank_code_patch = 0x2CF40; break; } // tweak the root heap start address to gain more overlay space :) m_FileStream.Position = mempatch1; uint lvl_start = m_BinReader.ReadUInt32(); uint lvl_end = lvl_start + LEVEL_OVERLAY_SIZE; m_FileStream.Position = mempatch1; m_BinWriter.Write(lvl_end); if (mempatch2 != 0xFFFFFFFF) { m_FileStream.Position = mempatch2; m_BinWriter.Write(lvl_end); } // patch level overlay unloading m_FileStream.Position = unload_patch; m_BinWriter.Write(unload_branchop); // patch more stuff foreach (uint addr in ovltable_addr_patch) { m_FileStream.Position = addr; m_BinWriter.Write((uint)(0x02000000 + levelptr_table)); } foreach (uint addr in ovltable_size_patch) { m_FileStream.Position = addr; uint op = m_BinReader.ReadUInt32(); op = (op & 0xFFFFFF00) | 0x0D; m_FileStream.Position = addr; m_BinWriter.Write(op); } lazyman.ReportProgress(201); // for each level, create a new overlay with the loader code and level data uint dataoffset = (uint)((loadercode.Length + 3) & ~3); for (int i = 0; i < 52; i++) { uint overlayid = AddOverlay(lvl_start); m_FileStream.Position = lvl_ovlid_table + (i*4); uint old_overlayid = m_BinReader.ReadUInt32(); m_FileStream.Position = lvl_ovlid_table + (i*4); m_BinWriter.Write(overlayid); NitroOverlay ovl = new NitroOverlay(this, overlayid); ovl.SetInitializer(lvl_start, 4); ovl.WriteBlock(0, loadercode); // write the object bank settings m_FileStream.Position = objbank_table + (i * 7); byte[] objbanks = m_BinReader.ReadBytes(7); ovl.WriteBlock(dataoffset, objbanks); ovl.Write8(dataoffset + 0x7, 0x00); ovl.Write32(dataoffset + 0x8, (uint)(i + 1)); // copy level data { NitroOverlay oldovl = new NitroOverlay(this, old_overlayid); uint oldbase = oldovl.GetRAMAddr(); m_FileStream.Position = levelptr_table + (i*4); uint header_offset = m_BinReader.ReadUInt32() - oldbase; uint curoffset = dataoffset + 0x40; // CLPS (collision behaviors) chunk { uint clps_addr = oldovl.ReadPointer(header_offset); ushort clps_num = oldovl.Read16(clps_addr + 0x06); uint clps_size = (uint)(8 + (clps_num * 8)); byte[] clps = oldovl.ReadBlock(clps_addr, clps_size); ovl.WriteBlock(curoffset, clps); ovl.WritePointer(dataoffset + 0x0C, curoffset); curoffset += clps_size; } // misc objects table list { uint tables_addr = oldovl.ReadPointer(header_offset + 0x4); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.WritePointer(dataoffset + 0x10, curoffset); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); int[] datasizes = {16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4}; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } // main object table lists // and that stuff about texture scrolling { uint tlists_addr = oldovl.ReadPointer(header_offset + 0x10); byte tlists_num = oldovl.Read8(header_offset + 0x14); uint tlists_new_addr = curoffset; curoffset += (uint)(tlists_num * 12); ovl.WritePointer(dataoffset + 0x1C, tlists_new_addr); ovl.Write8(dataoffset + 0x20, tlists_num); for (byte tl = 0; tl < tlists_num; tl++) { uint tables_addr = oldovl.ReadPointer(tlists_addr); uint texanm_addr = oldovl.ReadPointer(tlists_addr + 0x4); if (tables_addr != 0xFFFFFFFF) { ovl.WritePointer(tlists_new_addr, curoffset); ushort tables_num = oldovl.Read16(tables_addr); tables_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write16(curoffset, tables_num); ovl.WritePointer(curoffset + 0x04, curoffset + 0x8); curoffset += 0x8; uint objdata_offset = (uint)(curoffset + (tables_num * 8)); for (ushort t = 0; t < tables_num; t++) { uint tbl_part1 = oldovl.Read32(tables_addr); uint tbl_addr = oldovl.ReadPointer(tables_addr + 0x4); ovl.Write32(curoffset, tbl_part1); ovl.WritePointer(curoffset + 0x4, objdata_offset); tables_addr += 8; curoffset += 8; byte tbltype = (byte)(tbl_part1 & 0x1F); byte numentries = (byte)((tbl_part1 >> 8) & 0xFF); if ((tbltype == 13) || (tbltype > 14)) throw new Exception(String.Format("Wrong object table type {0} (0x{0:X2}) in level data", tbltype)); int[] datasizes = { 16, 16, 6, 6, 14, 8, 8, 8, 8, 12, 14, 2, 2, 0, 4 }; int datasize = numentries * datasizes[tbltype]; byte[] data = oldovl.ReadBlock(tbl_addr, (uint)datasize); ovl.WriteBlock(objdata_offset, data); objdata_offset += (uint)((datasize + 3) & ~3); } curoffset = objdata_offset; } else ovl.Write32(tlists_new_addr, 0); if (texanm_addr != 0xFFFFFFFF)//If not null { ovl.WritePointer(tlists_new_addr + 0x4, curoffset); uint texanm_new_addr = curoffset; curoffset += 0x18; uint textures_addr = oldovl.ReadPointer(texanm_addr + 0x14); uint numscale = 0, numrot = 0, numtrans = 0; uint numtextures = oldovl.Read32(texanm_addr + 0x10); ovl.Write32(texanm_new_addr, oldovl.Read32(texanm_addr)); ovl.Write32(texanm_new_addr + 0x10, numtextures); uint textures_new_addr = curoffset; curoffset += (numtextures * 0x1C); ovl.WritePointer(texanm_new_addr + 0x14, textures_new_addr); for (uint t = 0; t < numtextures; t++) { uint tex_old_addr = textures_addr + (t * 0x1C); uint tex_new_addr = textures_new_addr + (t * 0x1C); ushort tex_scalenum = oldovl.Read16(tex_old_addr + 0x0C); ushort tex_scalestart = oldovl.Read16(tex_old_addr + 0x0E); ushort tex_rotnum = oldovl.Read16(tex_old_addr + 0x10); ushort tex_rotstart = oldovl.Read16(tex_old_addr + 0x12); ushort tex_transnum = oldovl.Read16(tex_old_addr + 0x14); ushort tex_transstart = oldovl.Read16(tex_old_addr + 0x16); if ((tex_scalestart + tex_scalenum) > numscale) numscale = (uint)(tex_scalestart + tex_scalenum); if ((tex_rotstart + tex_rotnum) > numrot) numrot = (uint)(tex_rotstart + tex_rotnum); if ((tex_transstart + tex_transnum) > numtrans) numtrans = (uint)(tex_transstart + tex_transnum); ovl.Write32(tex_new_addr, oldovl.Read32(tex_old_addr)); ovl.WritePointer(tex_new_addr + 0x4, curoffset); ovl.Write32(tex_new_addr + 0x8, oldovl.Read32(tex_old_addr + 0x8)); ovl.Write16(tex_new_addr + 0xC, tex_scalenum); ovl.Write16(tex_new_addr + 0xE, tex_scalestart); ovl.Write16(tex_new_addr + 0x10, tex_rotnum); ovl.Write16(tex_new_addr + 0x12, tex_rotstart); ovl.Write16(tex_new_addr + 0x14, tex_transnum); ovl.Write16(tex_new_addr + 0x16, tex_transstart); ovl.Write32(tex_new_addr + 0x18, oldovl.Read32(tex_old_addr + 0x18)); string tex_matname = oldovl.ReadString(oldovl.ReadPointer(tex_old_addr + 0x4), 0); ovl.WriteString(curoffset, tex_matname, 0); curoffset += (uint)((tex_matname.Length + 3) & ~3); } uint scale_addr = oldovl.ReadPointer(texanm_addr + 0x4); ovl.WritePointer(texanm_new_addr + 0x4, curoffset); for (uint v = 0; v < numscale; v++) { ovl.Write32(curoffset, oldovl.Read32(scale_addr + (v * 4))); curoffset += 4; } uint rot_addr = oldovl.ReadPointer(texanm_addr + 0x8); ovl.WritePointer(texanm_new_addr + 0x8, curoffset); for (uint v = 0; v < numrot; v++) { ovl.Write16(curoffset, oldovl.Read16(rot_addr + (v * 2))); curoffset += 2; } curoffset = (uint)((curoffset + 3) & ~3); uint trans_addr = oldovl.ReadPointer(texanm_addr + 0xC); ovl.WritePointer(texanm_new_addr + 0xC, curoffset); for (uint v = 0; v < numtrans; v++) { ovl.Write32(curoffset, oldovl.Read32(trans_addr + (v * 4))); curoffset += 4; } } else ovl.Write32(tlists_new_addr + 0x4, 0); ovl.Write32(tlists_new_addr + 0x8, oldovl.Read32(tlists_addr + 0x8)); tlists_new_addr += 12; tlists_addr += 12; } } // misc header pieces ovl.Write32(dataoffset + 0x14, oldovl.Read32(header_offset + 0x8)); ovl.Write32(dataoffset + 0x18, oldovl.Read32(header_offset + 0xC)); ovl.Write16(dataoffset + 0x22, oldovl.Read16(header_offset + 0x16)); ovl.Write8(dataoffset + 0x24, oldovl.Read8(header_offset + 0x18)); } ovl.SaveChanges(); lazyman.ReportProgress(201 + (int)((98f / 54f) * i)); } // fix the level loader as to load from the new overlays m_FileStream.Position = lvlload_addr_patch; m_BinWriter.Write((uint)(lvl_start + dataoffset + 0xC)); m_FileStream.Position = lvlload_code_patch; m_BinWriter.Write((uint)0xE1A00000); // refill the old level header address table // to adapt it to its new usages m_FileStream.Position = levelptr_table; for (uint i = 0; i < 13; i++) { m_BinWriter.Write((uint)0xFFFFFFFF); m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); } m_BinWriter.Write((uint)0x00000000); m_BinWriter.Write((uint)0x00000000); // fix the object banks thingy m_FileStream.Position = objbank_addr_patch; m_BinWriter.Write((uint)(levelptr_table + 0x0200009C)); m_FileStream.Position = objbank_code_patch; m_BinWriter.Write((uint)0xE1A07001); // phew! what a goddamn long thing lazyman.ReportProgress(299); }
private void btnReplaceOverlay_Click(object sender, EventArgs e) { if (m_SelectedOverlay == null || m_SelectedOverlay.Equals("")) return; OpenFileDialog ofd = new OpenFileDialog(); if (ofd.ShowDialog() == DialogResult.Cancel) return; uint ovlID = uint.Parse(m_SelectedOverlay.Substring(8)); NitroOverlay ovl = new NitroOverlay(Program.m_ROM, ovlID); ovl.Clear(); ovl.WriteBlock(0, System.IO.File.ReadAllBytes(ofd.FileName)); ovl.SaveChanges(); }