Beispiel #1
0
        public LevelSettings(NitroOverlay ovl)
        {
            QuestionMarks  = (byte)(ovl.Read8(0x78) & 0xf);
            Background     = (byte)(ovl.Read8(0x78) >> 4);
            ObjectBanks    = new uint[8];
            ObjectBanks[0] = ovl.Read8(0x54);
            ObjectBanks[1] = ovl.Read8(0x55);
            ObjectBanks[2] = ovl.Read8(0x56);
            ObjectBanks[3] = ovl.Read8(0x57);
            ObjectBanks[4] = ovl.Read8(0x58);
            ObjectBanks[5] = ovl.Read8(0x59);
            ObjectBanks[6] = ovl.Read8(0x5A);
            ObjectBanks[7] = ovl.Read32(0x5C);

            BMDFileID         = ovl.Read16(0x68);
            KCLFileID         = ovl.Read16(0x6A);
            MinimapTsetFileID = ovl.Read16(0x6C);
            MinimapPalFileID  = ovl.Read16(0x6E);

            MusicBytes    = new byte[3];
            MusicBytes[0] = ovl.Read8(0x7C);
            MusicBytes[1] = ovl.Read8(0x7D);
            MusicBytes[2] = ovl.Read8(0x7E);

            MinimapCoordinateScale = ovl.Read16(0x76);
            CameraStartZoomedOut   = ovl.Read8(0x75);

            LevelFormatVersion        = (byte)(ovl.Read8(0x7F) & 0x0F);
            OverlayInitialiserVersion = (byte)(ovl.Read8(0x7F) >> 4);
        }
Beispiel #2
0
        public Level(int levelID, NitroOverlay overlay)
        {
            m_LevelID = levelID;
            m_Overlay = overlay;

            m_LevelSettings = new LevelSettings(m_Overlay);
            if (m_LevelSettings.LevelFormatVersion > k_LevelFormatVersion)
            {
                throw new InvalidDataException("This level was added by a later version of SM64DSe and cannot be read");
            }

            LoadCLPS(m_Overlay);

            // read object lists

            m_NumAreas = m_Overlay.Read8(0x74);
            uint objlistptr = m_Overlay.ReadPointer(0x70);

            m_LevelObjects = new Dictionary <uint, LevelObject>();
            m_TexAnims     = new List <LevelTexAnim>(8);
            for (int i = 0; i < 8; ++i)
            {
                m_TexAnims.Add(new LevelTexAnim(m_Overlay, i, m_NumAreas, m_LevelSettings.LevelFormatVersion));
            }

            m_DynLibIDs = new List <ushort>();
            if (DoesLevelUseDynamicLibs())
            {
                uint dlDataOffset = m_Overlay.Read32(0x30);
                uint numDLs       = m_Overlay.Read16(dlDataOffset);
                m_DynLibIDs = new List <ushort>((int)numDLs);
                for (uint i = 0; i < numDLs; ++i)
                {
                    m_DynLibIDs.Add(m_Overlay.Read16(dlDataOffset + 2 * i + 2));
                }
            }

            ReadObjectTable(m_Overlay, m_Overlay.ReadPointer(0x64), 0);
            m_MinimapIndices = new byte[k_MaxNumAreas];
            for (byte a = 0; a < m_NumAreas; a++)
            {
                // read object tables
                uint addr = (uint)(objlistptr + (a * 12));
                if (m_Overlay.Read32(addr) != 0)
                {
                    ReadObjectTable(m_Overlay, m_Overlay.ReadPointer(addr), a);
                }

                // texture animations, have already been read
                addr += 4;

                addr += 4;
                m_MinimapIndices[a] = m_Overlay.Read8(addr);
            }

            m_ObjAvailable = new Dictionary <ushort, bool>();
            DetermineAvailableObjects();
        }
Beispiel #3
0
        private void copyCLPS(int sourceLevel)
        {
            NitroOverlay otherOVL = new NitroOverlay(Program.m_ROM, Program.m_ROM.GetLevelOverlayID(sourceLevel));

            uint   other_clps_addr = otherOVL.ReadPointer(0x60);
            ushort other_clps_num  = otherOVL.Read16(other_clps_addr + 0x06);
            uint   other_clps_size = (uint)(8 + (other_clps_num * 8));

            uint   clps_addr = _owner.m_Overlay.ReadPointer(0x60);
            ushort clps_num  = _owner.m_Overlay.Read16(clps_addr + 0x06);
            uint   clps_size = (uint)(8 + (clps_num * 8));

            byte[] CLPS_data = otherOVL.ReadBlock(other_clps_addr, other_clps_size);

            // Make or remove room for other CLPS table
            if (clps_size < other_clps_size)
            {
                AddSpace(clps_addr + clps_size, other_clps_size - clps_size);
            }
            else if (clps_size > other_clps_size)
            {
                RemoveSpace(clps_addr + clps_size - (clps_size - other_clps_size), clps_size - other_clps_size);
            }

            // Write CLPS table from overlay
            _owner.m_Overlay.WriteBlock(clps_addr, CLPS_data);

            loadCLPSData();
        }
Beispiel #4
0
        private void btnKCLEditor_Click(object sender, EventArgs e)
        {
            uint          ovlID   = Program.m_ROM.GetLevelOverlayID(lbxLevels.SelectedIndex);
            NitroOverlay  curOvl  = new NitroOverlay(Program.m_ROM, ovlID);
            NitroFile     curKCL  = Program.m_ROM.GetFileFromInternalID(curOvl.Read16((uint)(0x6A)));
            KCLEditorForm kclForm = new KCLEditorForm(curKCL);

            kclForm.Show();
        }
Beispiel #5
0
        private void LoadCLPS(NitroOverlay ovl)
        {
            uint clpsAddr  = ovl.ReadPointer(0x60);
            int  numCLPSes = ovl.Read16(clpsAddr + 0x06);

            m_CLPS = new CLPS();

            clpsAddr += 8;
            for (int i = 0; i < numCLPSes; ++i)
            {
                CLPS.Entry clps = new CLPS.Entry();
                clps.flags  = ovl.Read32(clpsAddr);
                clps.flags |= (ulong)ovl.Read32(clpsAddr + 4) << 32;
                m_CLPS.Add(clps);
                clpsAddr += 8;
            }
        }
Beispiel #6
0
        private void btnEditCollisionMap_Click(object sender, EventArgs e)
        {
            uint         overlayID      = Program.m_ROM.GetLevelOverlayID(lbxLevels.SelectedIndex);
            NitroOverlay currentOverlay = new NitroOverlay(Program.m_ROM, overlayID);
            NitroFile    currentKCL     = Program.m_ROM.GetFileFromInternalID(currentOverlay.Read16((uint)(0x6A)));

            if (!Properties.Settings.Default.UseSimpleModelAndCollisionMapImporters)
            {
                ModelAndCollisionMapEditor kclForm =
                    new ModelAndCollisionMapEditor(null, currentKCL.m_Name, 1f, ModelAndCollisionMapEditor.StartMode.CollisionMap);
                kclForm.Show();
            }
            else
            {
                KCLEditorForm kclForm = new KCLEditorForm(currentKCL);
                kclForm.Show();
            }
        }
Beispiel #7
0
        private void CopyCLPS(int sourceLevel)
        {
            NitroOverlay otherOVL = new NitroOverlay(Program.m_ROM, Program.m_ROM.GetLevelOverlayID(sourceLevel));

            uint   other_clps_addr = otherOVL.ReadPointer(0x60);
            ushort other_clps_num  = otherOVL.Read16(other_clps_addr + 0x06);
            uint   other_clps_size = (uint)(8 + (other_clps_num * 8));

            m_CLPS = new CLPS();
            for (int i = 0; i < other_clps_num; ++i)
            {
                ulong flags = otherOVL.Read32((uint)(other_clps_addr + 8 + 8 * i + 0));
                flags |= (ulong)otherOVL.Read32((uint)(other_clps_addr + 8 + 8 * i + 4)) << 32;
                CLPS.Entry clps = new CLPS.Entry();
                clps.flags = flags;
                m_CLPS.Add(clps);
            }

            LoadCLPSData();
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        private void ReadObjectTable(NitroOverlay ovl, uint offset, int area)
        {
            uint subtbl_num    = ovl.Read32(offset);
            uint subtbl_offset = ovl.ReadPointer(offset + 0x4);

            for (uint st = 0; st < subtbl_num; st++)
            {
                uint curoffset = subtbl_offset + (st * 8);

                byte flags          = ovl.Read8(curoffset);
                byte entries_num    = ovl.Read8(curoffset + 0x1);
                uint entries_offset = ovl.ReadPointer(curoffset + 0x4);

                byte type  = (byte)(flags & 0x1F);
                byte layer = (byte)(flags >> 5);

                if (type == 11)
                {
                    m_MinimapFileIDs = new ushort[entries_num];
                }

                for (byte e = 0; e < entries_num; ++e)
                {
                    LevelObject    obj;
                    INitroROMBlock objData = new INitroROMBlock();
                    objData.m_Data = ovl.ReadBlock((uint)(entries_offset + e * k_LevelObjTypeSizes[type]), (uint)k_LevelObjTypeSizes[type]);
                    switch (type)
                    {
                    case 0:
                        obj = new StandardObject(objData, m_LevelObjects.Count, layer, area);
                        break;

                    case 1:
                        obj = new EntranceObject(objData, m_LevelObjects.Count, layer, m_EntranceID++);
                        break;

                    case 2:     // Path Node
                        obj = new PathPointObject(objData, m_LevelObjects.Count, m_PathNodeID++);
                        break;

                    case 3:     // Path
                        obj = new PathObject(objData, m_LevelObjects.Count, (ushort)m_PathID++);
                        break;

                    case 4:
                        obj = new ViewObject(objData, m_LevelObjects.Count, m_ViewID++);
                        break;

                    case 5:
                        obj = new SimpleObject(objData, m_LevelObjects.Count, layer, area);
                        break;

                    case 6:
                        obj = new TpSrcObject(objData, m_LevelObjects.Count, layer);
                        break;

                    case 7:
                        obj = new TpDstObject(objData, m_LevelObjects.Count, layer);
                        break;

                    case 8:
                        // Fog
                        obj = new FogObject(objData, m_LevelObjects.Count, layer, area);
                        break;

                    case 9:
                        obj = new DoorObject(objData, m_LevelObjects.Count, layer);
                        break;

                    case 10:
                        obj = new ExitObject(objData, m_LevelObjects.Count, layer);
                        break;

                    case 11:
                        obj = new MinimapTileIDObject(objData, m_LevelObjects.Count, layer, m_MinimapTileIDNum++);
                        // This is still used by Minimap Editor
                        m_MinimapFileIDs[e] = ovl.Read16((uint)(entries_offset + (e * 2)));
                        break;

                    case 12:
                        // per-area minimap scale factors
                        obj = new MinimapScaleObject(objData, m_LevelObjects.Count, layer, area);
                        break;

                    case 14:
                        // ??? Unknown
                        obj = new Type14Object(objData, m_LevelObjects.Count, layer, area);
                        break;

                    default:
                        throw new InvalidDataException("Bad object type: " + type);
                    }

                    m_LevelObjects.Add(obj.m_UniqueID, obj);
                }
            }
        }
Beispiel #10
0
        public void DumpObjectInfo()
        {
            uint actorptrtable = 0x8000 + 0x88864;

            Program.m_ROM.BeginRW();

            Stream fs = File.Create("objinfo.php");
            StreamWriter wr = new StreamWriter(fs);

            wr.Write("<?php\n$objinfo = array\n(\n");

            for (int i = 0; i < 0x146; i++)
            {
                wr.Write("\tarray\n\t(\n");

                wr.Write(String.Format("\t\t'id' => 0x{0:X4},\n", i));
                wr.Write("\t\t'internalname' => '" + ObjectDatabase.m_ObjectInfo[i].m_InternalName + "',\n");

                uint actorid = ObjectDatabase.m_ObjectInfo[i].m_ActorID;
                uint actoraddr = Program.m_ROM.Read32(actorptrtable + (uint)(actorid * 4));

                wr.Write(String.Format("\t\t'actorid' => 0x{0:X4},\n", actorid));

                if (actoraddr < 0x021111A0)
                    wr.Write("\t\t'requirement' => 'none',\n");
                else
                {
                    uint minovl = 0, maxovl = 0, bank = 0, bankbase = 0;
                    if ((actoraddr >= 0x021111A0) && (actoraddr < 0x02115EE0))
                    { minovl = 8; maxovl = 59; bank = 7; bankbase = 1;  }
                    else if ((actoraddr >= 0x02115EE0) && (actoraddr < 0x0211F000))
                    { minovl = 0x3E; maxovl = 0x42; bank = 0; bankbase = 1;  }
                    else if ((actoraddr >= 0x0211F000) && (actoraddr < 0x02123740))
                    { minovl = 0x46; maxovl = 0x4A; bank = 1; bankbase = 2; }
                    else if ((actoraddr >= 0x02123740) && (actoraddr < 0x02129020))
                    { minovl = 0x4D; maxovl = 0x51; bank = 2; bankbase = 1; }
                    else if ((actoraddr >= 0x02129020) && (actoraddr < 0x02130F00))
                    { minovl = 0x54; maxovl = 0x55; bank = 3; bankbase = 1; }
                    else if ((actoraddr >= 0x02130F00) && (actoraddr < 0x02135700))
                    { minovl = 0x59; maxovl = 0x5C; bank = 4; bankbase = 1; }
                    else if ((actoraddr >= 0x02135700) && (actoraddr < 0x02140D80))
                    { minovl = 0x5E; maxovl = 0x61; bank = 5; bankbase = 1; }
                    else if ((actoraddr >= 0x02140D80) && (actoraddr < 0x0214EAA0))
                    { minovl = 0x64; maxovl = 0x64; bank = 6; bankbase = 1; }

                    uint curovl = minovl;
                    do
                    {
                        NitroOverlay theovl = new NitroOverlay(Program.m_ROM, curovl);

                        uint testval = 0xFFFFFFFF;
                        try { testval = (uint)theovl.Read16(actoraddr - theovl.GetRAMAddr() + 4); }
                        catch {}

                        if (testval == actorid)
                        {
                            wr.Write(String.Format("\t\t'requirement' => 'bank{0}={1}',\n", bank, curovl - minovl + bankbase));

                            break;
                        }

                        curovl++;
                    }
                    while (curovl <= maxovl);
                }

                wr.Write("\t\t0\n\t), \n");
                if ((i % 64) == 0) wr.Flush();
            }

            wr.Write("\t0\n);\n?>\n");
            wr.Flush();

            fs.Close();
            Program.m_ROM.EndRW();
        }
Beispiel #11
0
        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);
        }
Beispiel #12
0
        private void copyCLPS(int sourceLevel)
        {
            NitroOverlay otherOVL = new NitroOverlay(Program.m_ROM, Program.m_ROM.GetLevelOverlayID(sourceLevel));

            uint other_clps_addr = otherOVL.ReadPointer(0x60);
            ushort other_clps_num = otherOVL.Read16(other_clps_addr + 0x06);
            uint other_clps_size = (uint)(8 + (other_clps_num * 8));

            uint clps_addr = _owner.m_Overlay.ReadPointer(0x60);
            ushort clps_num = _owner.m_Overlay.Read16(clps_addr + 0x06);
            uint clps_size = (uint)(8 + (clps_num * 8));

            byte[] CLPS_data = otherOVL.ReadBlock(other_clps_addr, other_clps_size);

            // Make or remove room for other CLPS table
            if (clps_size < other_clps_size)
            {
                AddSpace(clps_addr + clps_size, other_clps_size - clps_size);
            }
            else if (clps_size > other_clps_size)
            {
                RemoveSpace(clps_addr + clps_size - (clps_size - other_clps_size), clps_size - other_clps_size);
            }

            // Write CLPS table from overlay
            _owner.m_Overlay.WriteBlock(clps_addr, CLPS_data);

            loadCLPSData();
        }
Beispiel #13
0
 private void btnKCLEditor_Click(object sender, EventArgs e)
 {
     uint ovlID = Program.m_ROM.GetLevelOverlayID(lbxLevels.SelectedIndex);
     NitroOverlay curOvl = new NitroOverlay(Program.m_ROM, ovlID);
     NitroFile curKCL = Program.m_ROM.GetFileFromInternalID(curOvl.Read16((uint)(0x6A)));
     KCLEditorForm kclForm = new KCLEditorForm(curKCL);
     kclForm.Show();
 }
Beispiel #14
0
        public void DumpObjectInfo()
        {
            uint actorptrtable = 0x8000 + 0x88864;

            Program.m_ROM.BeginRW();

            Stream       fs = File.Create("objinfo.php");
            StreamWriter wr = new StreamWriter(fs);

            wr.Write("<?php\n$objinfo = array\n(\n");

            for (int i = 0; i < 0x146; i++)
            {
                wr.Write("\tarray\n\t(\n");

                wr.Write(String.Format("\t\t'id' => 0x{0:X4},\n", i));
                wr.Write("\t\t'internalname' => '" + ObjectDatabase.m_ObjectInfo[i].m_InternalName + "',\n");

                uint actorid   = ObjectDatabase.m_ObjectInfo[i].m_ActorID;
                uint actoraddr = Program.m_ROM.Read32(actorptrtable + (uint)(actorid * 4));

                wr.Write(String.Format("\t\t'actorid' => 0x{0:X4},\n", actorid));

                if (actoraddr < 0x021111A0)
                {
                    wr.Write("\t\t'requirement' => 'none',\n");
                }
                else
                {
                    uint minovl = 0, maxovl = 0, bank = 0, bankbase = 0;
                    if ((actoraddr >= 0x021111A0) && (actoraddr < 0x02115EE0))
                    {
                        minovl = 8; maxovl = 59; bank = 7; bankbase = 1;
                    }
                    else if ((actoraddr >= 0x02115EE0) && (actoraddr < 0x0211F000))
                    {
                        minovl = 0x3E; maxovl = 0x42; bank = 0; bankbase = 1;
                    }
                    else if ((actoraddr >= 0x0211F000) && (actoraddr < 0x02123740))
                    {
                        minovl = 0x46; maxovl = 0x4A; bank = 1; bankbase = 2;
                    }
                    else if ((actoraddr >= 0x02123740) && (actoraddr < 0x02129020))
                    {
                        minovl = 0x4D; maxovl = 0x51; bank = 2; bankbase = 1;
                    }
                    else if ((actoraddr >= 0x02129020) && (actoraddr < 0x02130F00))
                    {
                        minovl = 0x54; maxovl = 0x55; bank = 3; bankbase = 1;
                    }
                    else if ((actoraddr >= 0x02130F00) && (actoraddr < 0x02135700))
                    {
                        minovl = 0x59; maxovl = 0x5C; bank = 4; bankbase = 1;
                    }
                    else if ((actoraddr >= 0x02135700) && (actoraddr < 0x02140D80))
                    {
                        minovl = 0x5E; maxovl = 0x61; bank = 5; bankbase = 1;
                    }
                    else if ((actoraddr >= 0x02140D80) && (actoraddr < 0x0214EAA0))
                    {
                        minovl = 0x64; maxovl = 0x64; bank = 6; bankbase = 1;
                    }

                    uint curovl = minovl;
                    do
                    {
                        NitroOverlay theovl = new NitroOverlay(Program.m_ROM, curovl);

                        uint testval = 0xFFFFFFFF;
                        try { testval = (uint)theovl.Read16(actoraddr - theovl.GetRAMAddr() + 4); }
                        catch {}

                        if (testval == actorid)
                        {
                            wr.Write(String.Format("\t\t'requirement' => 'bank{0}={1}',\n", bank, curovl - minovl + bankbase));

                            break;
                        }

                        curovl++;
                    }while (curovl <= maxovl);
                }

                wr.Write("\t\t0\n\t), \n");
                if ((i % 64) == 0)
                {
                    wr.Flush();
                }
            }

            wr.Write("\t0\n);\n?>\n");
            wr.Flush();

            fs.Close();
            Program.m_ROM.EndRW();
        }
Beispiel #15
0
        public LevelTexAnim(NitroOverlay ovl, uint tbloffset, uint offset, int num, int area)
        {
            m_Overlay = ovl;
            // Address of the animation data
            m_Offset = offset;
            m_UniqueID = (uint)num;
            m_Area = area;
            // Address of the texture animation data header for this texture animation
            m_TexAnimHeaderOffset = tbloffset;

            // Addresses at which the scale, rotation and translation data for this texture animation starts
            m_ScaleTblOffset = m_Overlay.ReadPointer(tbloffset + 0x4) + (uint)(m_Overlay.Read16(m_Offset + 0xE) * 4);
            m_RotTblOffset = m_Overlay.ReadPointer(tbloffset + 0x8) + (uint)(m_Overlay.Read16(m_Offset + 0x12) * 2);
            m_TransTblOffset = m_Overlay.ReadPointer(tbloffset + 0xC) + (uint)(m_Overlay.Read16(m_Offset + 0x16) * 4);

            // Addresses of the shared scale, rotation and translation tables
            m_BaseScaleTblAddr = m_Overlay.ReadPointer(tbloffset + 0x4);
            m_BaseRotTblAddr = m_Overlay.ReadPointer(tbloffset + 0x8);
            m_BaseTransTblAddr = m_Overlay.ReadPointer(tbloffset + 0xC);

            m_MatNameOffset = m_Overlay.ReadPointer(m_Offset + 0x4);
        }
Beispiel #16
0
        public LevelSettings(NitroOverlay ovl)
        {
            m_Overlay = ovl;
            Background = (byte)(m_Overlay.Read8(0x78) >> 4);
            ObjectBanks = new uint[8];
            ObjectBanks[0] = m_Overlay.Read8(0x54);
            ObjectBanks[1] = m_Overlay.Read8(0x55);
            ObjectBanks[2] = m_Overlay.Read8(0x56);
            ObjectBanks[3] = m_Overlay.Read8(0x57);
            ObjectBanks[4] = m_Overlay.Read8(0x58);
            ObjectBanks[5] = m_Overlay.Read8(0x59);
            ObjectBanks[6] = m_Overlay.Read8(0x5A);
            ObjectBanks[7] = m_Overlay.Read32(0x5C);

            BMDFileID = m_Overlay.Read16(0x68);
            KCLFileID = m_Overlay.Read16(0x6A);
            MinimapTsetFileID = m_Overlay.Read16(0x6C);
            MinimapPalFileID = m_Overlay.Read16(0x6E);

            MusicBytes = new byte[3];
            MusicBytes[0] = m_Overlay.Read8(0x7C);
            MusicBytes[1] = m_Overlay.Read8(0x7D);
            MusicBytes[2] = m_Overlay.Read8(0x7E);

            MinimapCoordinateScale = m_Overlay.Read16(0x76);
            CameraStartZoomedOut = m_Overlay.Read8(0x75);
        }