Beispiel #1
0
        private void UpdateItemLinkedList()
        {
            int dist = itemData.DataMoveDist;

            var pointerToData = Expander.pointers.ItemData.AsPRom(level); // Offset of program pointer to first item
            var itemPointer   = new pCpu(newRomData, pointerToData);      // Address of first item
            var dataOffset    = itemPointer.AsPRom(level);                // Offset of first item

            bool done = false;

            while (!done)
            {
                var  OffsetOfpNext = dataOffset + 1;
                pCpu pNext         = new pCpu(newRomData, OffsetOfpNext);

                done |= pNext.Value == 0xFFFF;
                if (!done)
                {
                    // Update pointer to next item to where item data will be moved to
                    pCpu updatedPNext = pNext + dist;
                    updatedPNext.Write(newRomData, OffsetOfpNext);
                    // Update dataOffset to point to next item
                    dataOffset = pNext.AsPRom(level);
                }
            }
        }
        private void LoadStructs()
        {
            PtableBank = level.Format.StructPtableBank;
            DataBank   = level.Format.StructDataBank;
            structs    = new Structure[level.Format.CalculateStructCount()];

            MemoryStream stream = new MemoryStream(level.Rom.data);

            // Get the location of the first struct pointer
            pCpu ppStructTable = level.Format.pPointerToStructPTable;
            pCpu pStructTable  = level.Bank.GetPtr(ppStructTable);

            // For all struct pointers
            for (int i = 0; i < structs.Length; i++)
            {
                // Load the pointer
                pCpu pStruct = PtableBank.GetPtr(pStructTable + i * 2);

                // Resolve the pointer to an offset and use that to load the struct
                pRom StructOffset = DataBank.ToOffset(pStruct);
                structs[i] = new Structure(level, i);
                //structs[i].Offset = StructOffset;
                stream.Seek((int)StructOffset, SeekOrigin.Begin);
                structs[i].LoadData(stream);
            }
        }
Beispiel #3
0
        public void SetPtr(pCpu address, pCpu value)
        {
            var offset = ToOffset(address);

            Rom.data[offset]     = value.Byte1;
            Rom.data[offset + 1] = value.Byte2;
        }
Beispiel #4
0
        public override void PerformSaveOperation(ILevelDataSerializer saver)
        {
            // Implements expando behavior

            // Struct pTable location is fixed
            int structTableOffset = (int)StructPtableOffset;
            // Struct0 location is fixed, get from pointer table
            pCpu pStructData      = Level.Rom.GetPointer((pRom)structTableOffset);
            int  structDataOffset = (int)Level.Structures.DataBank.ToOffset(pStructData);

            // Room pTable location is fixed
            int roomTableOffset = (int)RoomPtableOffset;
            // Room0 location is fixed, get from pointer table
            pCpu pRoomData      = Level.Rom.GetPointer((pRom)roomTableOffset);
            int  roomDataOffset = (int)Level.Screens.DataBank.ToOffset(pRoomData);

            // We serialize structs before their pointers so they can calculate and cache their offsets
            var refStructDataOffset = structDataOffset;

            saver.SerializeStructData(ref refStructDataOffset);
            saver.SerializeStructTable(ref structTableOffset);

            // Serialize rooms before pointers so they can calculate offsets
            var refRoomDataOffset = roomDataOffset;

            saver.SerializeRoomData(ref refRoomDataOffset);
            saver.SerializeRoomTable(ref roomTableOffset);
        }
Beispiel #5
0
        /// <summary>
        /// Returns an EditorData object loaded from the ROM, or null if the ROM does not contain an EditorData section.
        /// If the ROM does not contain an EditorData section, a new EditorData object can be created via the
        /// CreateNewForROM function.
        /// </summary>
        public static EditorData LoadEditorData(MetroidRom rom)
        {
            if (rom.Banks.Count < 0xe)
            {
                return(null);
            }
            var  dataBank = rom.Banks[0xe];
            pCpu pData    = RomFormat.EditorDataPointer;

            for (int i = 0; i < MagicNumber.Length; i++)
            {
                if (dataBank[pData] != MagicNumber[i])
                {
                    return(null);
                }

                pData += 1;
            }

            EditorData result = new EditorData(rom);

            using (var r = new BinaryReader(new MemoryStream(rom.data, dataBank.ToOffset(pData), 0x4000))) {
                result.VersionMajor         = r.ReadByte();
                result.VersionMinor         = r.ReadByte();
                result.HasAssociatedProject = r.ReadBoolean();
            }
            return(result);
        }
Beispiel #6
0
 public byte this[pCpu p] {
     get {
         return(Rom.data[Offset + p.BankedOffset]);
     }
     set {
         Rom.data[Offset + p.BankedOffset] = value;
     }
 }
Beispiel #7
0
 public T this[pCpu address] {
     get {
         int offset = address.Value + netBankOffset;
         return(this[offset]);
     }
     set {
         int offset = address.Value + netBankOffset;
         this[offset] = value;
     }
 }
Beispiel #8
0
        private void LoadScreens()
        {
            // **** The original game contains a few duplicate pointers. We have to deal
            // with them a certain way to keep screen, map, and pointer data consistient
            // and avoid overflows. When we find consecutive duplicate pointers, we only load
            // screen data for the last of the duplicates, and the rest are interpreted as
            // empty screens. When the screens are saved back to the ROM, if they are still
            // empty, they are written as zero bytes, which reproduces the doubled pointers.

            // Get the location of the first screen pointer
            var ppRoomTable = Level.Format.pPointerToRoomPTable;
            var pRoomTable  = Level.Bank.GetPtr(ppRoomTable);

            int roomPtrCount = Level.Format.CalculateRoomCount();

            ////pCpu pPrevRoom = new pCpu(0);

            for (int i = 0; i < roomPtrCount; i++)
            {
                pCpu pRoom     = Pointers[i];
                pCpu pNextRoom = Pointers[i + 1];
                //pCpu pRoom = PointerBank.GetPtr(pRoomTable + i * 2);
                //pCpu pNextRoom = PointerBank.GetPtr(pRoomTable + (i + 1) * 2);

                bool doubledPointer = pRoom.Value == pNextRoom.Value;

                var newScreen = new Screen(Level.Rom, this);
                Add(newScreen);

                if (doubledPointer)
                {
                    // Mark doubled pointers, and don't load data for the duplicates
                    _invalidScreenIndecies.Add(i);
                    newScreen.Offset = Level.Bank.ToOffset(pRoom);
                }
                else
                {
                    newScreen.LoadFromRom();
                }

                ////pPrevRoom = pRoom;
            }


            ////// Clear out unused pointers
            ////pCpu nullPtr = new pCpu(0xFFFF);
            ////for (int i = Count; i < roomPtrCount; i++) {
            ////    PointerBank.SetPtr(pRoomTable + i * 2, nullPtr);

            ////}
        }
Beispiel #9
0
        private void UpdatePointers(int moveIndex)
        {
            var move = moveQueue[moveIndex];

            // Update pointers
            int offsetDiff = move.pDest - move.pSource;

            for (int iPointer = 0; iPointer < move.ptableCount; iPointer++)
            {
                var pointerOffset = move.pPTable + 2 * iPointer;
                var pointerValue  = new pCpu(newRomData, (int)pointerOffset);
                pointerValue += offsetDiff;
                pointerValue.Write(newRomData, pointerOffset);
            }
        }
Beispiel #10
0
        private pRom GetOffsetOfFirstPalEntry(Level level)
        {
            pCpu pFirst = (pCpu)0xFFFF;

            for (int i = 0; i < Expander.pointers.PalPointerCount; i++)
            {
                var pData = level.PalettePointers[i];
                if (pData < pFirst)
                {
                    pFirst = pData;
                }
            }

            return(pFirst.AsPRom(level));
        }
Beispiel #11
0
        private void RelocateLevelsAltPalette(Level level)
        {
            byte[] palData = new byte[0x20];

            var pPal0 = level.PalettePointers[0];
            var pPal5 = level.PalettePointers[5];

            var oPal0 = level.Bank.ToOffset(pPal0);
            var oPal5 = level.Bank.ToOffset(pPal5);

            // We initialize the alternate palette with data from the normal palette
            // because the alt pal effectively falls back to normal palette values for
            // palette enttries not specified in alt pal.
            ApplyPalData(palData, oPal0);
            // Then we apply any alt pal data.
            ApplyPalData(palData, oPal5);

            var oNewPalData = level.Bank.ToOffset(pNewAltPal);

            // PPU dest = $3F00
            enhancedRomData[oNewPalData] = 0x3F;
            oNewPalData++;
            enhancedRomData[oNewPalData] = 0x00;
            oNewPalData++;

            // Data length = $20
            enhancedRomData[oNewPalData] = 0x20;
            oNewPalData++;

            // Actual pal data
            for (int i = 0; i < palData.Length; i++)
            {
                enhancedRomData[oNewPalData] = palData[i];
                oNewPalData++;
            }

            // 00 - PPU string list terminator
            enhancedRomData[oNewPalData] = 0x00;
            oNewPalData++;

            // Pointer to the newly created palette data
            var ppAltPal = new pCpu(0x956A);              // Address of alt pal pointer
            var opAltPal = level.Bank.ToOffset(ppAltPal); // Offset of pointer

            pNewAltPal.Write(enhancedRomData, opAltPal);
        }
Beispiel #12
0
        /// <summary>
        /// DONT CALL THIS METHOD ON UNEXPANDED ROMS OR IT WILL ASPLODE.
        /// </summary>
        public void SaveEditorData()
        {
            var  dataBank = rom.Banks[0xe];
            pCpu pData    = RomFormat.EditorDataPointer;

            for (int i = 0; i < MagicNumber.Length; i++)
            {
                dataBank[pData] = MagicNumber[i];
                pData          += 1;
            }

            using (var w = new BinaryWriter(new MemoryStream(rom.data, dataBank.ToOffset(pData), 0x4000))) {
                w.Write(VersionMajor);
                w.Write(VersionMinor);
                w.Write(HasAssociatedProject);
            }
        }
Beispiel #13
0
        public pRom ToOffset(pCpu ptr)
        {
#if DEBUG
            if (Fixed)
            {
                if (ptr.Value < 0xC000)
                {
                    System.Diagnostics.Debug.Fail("Attempted to deref fixed-bank-pointer in non-fixed bank");
                }
            }
            else
            {
                if (ptr.Value >= 0xC000)
                {
                    //System.Diagnostics.Debug.Fail("Attempted to deref nonfixed-bank-pointer in fixed bank");
                }
            }
#endif
            return((pRom)Offset + ptr.BankedOffset);
        }
Beispiel #14
0
        private int GetFreeMemInRoomBank()
        {
            // (We don't consider the memory used by combos since they are fixed in size and location)

            // Data starts with the struct table and ends at the end of the bank.
            pCpu memStart = Level.Bank.GetPtr(pPointerToStructPTable);
            pCpu memEnd   = (pCpu)0xC000;

            int memSize = memEnd - memStart;

            // subtract memory that is in use
            memSize -= Level.StructCount * 2; // Struct pTable uses two bytes per struct
            for (int i = 0; i < Level.Structures.Count; i++)
            {
                memSize -= Level.Structures[i].Size;
            }
            for (int i = 0; i < Level.Screens.Count; i++)
            {
                memSize -= Level.Screens[i].Size;
            }

            return(memSize);
        }
Beispiel #15
0
 public pCpu GetPtr(pCpu address)
 {
     return(new pCpu(Rom.data, ToOffset(address)));
 }
Beispiel #16
0
        pCpu enhanced_GetPtr(int bankOffset, pCpu address)
        {
            int offset = bankOffset + (address.Value & 0x3FFF);

            return(new pCpu(enhancedRomData, offset));
        }
Beispiel #17
0
 public void SetPointers(Level level, pCpu ppPTable, int pointerCount)
 {
     this.pPTable     = ppPTable.AsPRom(level);
     this.ptableCount = pointerCount;
     this.pSource     = level.DerefHandle(ppPTable);
 }
Beispiel #18
0
        /// <summary>
        /// Finds the offset of a pointer table and its associated data, given the offset of the game's pointer to the pointer table.
        /// </summary>
        /// <param name="level"></param>
        /// <param name="pointers"></param>
        /// <param name="data"></param>
        /// <param name="pointerCount">Specifies the number of pointers in the pointer table. This is used to init pointers.length and data.pointerCount.</param>
        /// <param name="pTablePointer"></param>
        void FindPointersAndData(Level level, DataSegment pointers, DataSegment data, pCpu pTablePointer, int pointerCount)
        {
            pointers.pPTable     = pTablePointer.AsPRom(level);
            pointers.ptableCount = 1;
            pointers.length      = pointerCount * 2;
            pointers.pSource     = level.DerefHandle(pointers.pPTable);

            data.pPTable     = pointers.pSource;
            data.ptableCount = pointerCount;
            data.pSource     = level.DerefHandle(data.pPTable);
        }
Beispiel #19
0
        void enhanced_SetPtr(int bankOffset, pCpu location, pCpu value)
        {
            int offset = bankOffset + (location.Value & 0x3FFF);

            value.Write(enhancedRomData, offset);
        }
Beispiel #20
0
 private EditorData(MetroidRom rom, pCpu firstByteAfterMagicNumber)
 {
     this.rom = rom;
 }