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); } }
public void SetPtr(pCpu address, pCpu value) { var offset = ToOffset(address); Rom.data[offset] = value.Byte1; Rom.data[offset + 1] = value.Byte2; }
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); }
/// <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); }
public byte this[pCpu p] { get { return(Rom.data[Offset + p.BankedOffset]); } set { Rom.data[Offset + p.BankedOffset] = value; } }
public T this[pCpu address] { get { int offset = address.Value + netBankOffset; return(this[offset]); } set { int offset = address.Value + netBankOffset; this[offset] = value; } }
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); ////} }
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); } }
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)); }
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); }
/// <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); } }
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); }
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); }
public pCpu GetPtr(pCpu address) { return(new pCpu(Rom.data, ToOffset(address))); }
pCpu enhanced_GetPtr(int bankOffset, pCpu address) { int offset = bankOffset + (address.Value & 0x3FFF); return(new pCpu(enhancedRomData, offset)); }
public void SetPointers(Level level, pCpu ppPTable, int pointerCount) { this.pPTable = ppPTable.AsPRom(level); this.ptableCount = pointerCount; this.pSource = level.DerefHandle(ppPTable); }
/// <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); }
void enhanced_SetPtr(int bankOffset, pCpu location, pCpu value) { int offset = bankOffset + (location.Value & 0x3FFF); value.Write(enhancedRomData, offset); }
private EditorData(MetroidRom rom, pCpu firstByteAfterMagicNumber) { this.rom = rom; }