Пример #1
0
        public static void WriteToROM(int Addr, ushort val)
        {
            int f    = RomUtils.GetFileIndexForWriting(Addr);
            int dest = Addr - RomData.MMFileList[f].Addr;
            var data = new byte[]
            {
                (byte)((val & 0xFF00) >> 8),
                (byte)(val & 0xFF)
            };

            Arr_Insert(data, 0, data.Length, RomData.MMFileList[f].Data, dest);
        }
Пример #2
0
        public static int AddNewFile(string path, string filename)
        {
            byte[] buffer;
            using (BinaryReader data = new BinaryReader(File.OpenRead(Path.Combine(path, filename))))
            {
                int len = (int)data.BaseStream.Length;
                buffer = new byte[len];
                data.Read(buffer, 0, len);
            }
            int index = RomUtils.AppendFile(buffer);

            return(RomData.MMFileList[index].Addr);
        }
Пример #3
0
 public static void ReenableNightBGMSingle(int SceneFileID, byte NewMusicByte = 0x13)
 {
     // search for the bgm music header in the scene headers and replace the night sfx with a value that plays day BGM
     RomUtils.CheckCompressed(SceneFileID);
     for (int Byte = 0; Byte < 0x10 * 70; Byte += 8)
     {
         if (RomData.MMFileList[SceneFileID].Data[Byte] == 0x15)              // header command starts with 0x15
         {
             RomData.MMFileList[SceneFileID].Data[Byte + 0x6] = NewMusicByte; // 6th/8 byte is night BGM behavior, 0x13 is daytime BGM
             return;
         }
     }
 }
Пример #4
0
        public static void ReassignSkulltulaHousesMusic(byte replacement_slot = 0x75)
        {
            // changes the skulltulla house BGM to a separate slot so it plays a new music that isn't generic cave music (overused)
            // the BGM for a scene is specified by a single byte in the scene headers

            // to modify the scene header, which is in the scene, we need the scene as a file
            //  we can get this from the Romdata.SceneList but this only gets populated on enemizer
            //  and we don't NEED to populate it since vanilla scenes are static, we can just hard code it here
            //  at re-encode, we'll have fewer decoded files to re-encode too
            int swamp_spider_house_fid = 1284; // taken from ultimate MM spreadsheet (US File list -> A column)

            // scan the files for the header that contains scene music (0x15 first byte)
            // 15xx0000 0000yyzz where zz is the sequence pointer byte
            RomUtils.CheckCompressed(swamp_spider_house_fid);
            for (int b = 0; b < 0x10 * 70; b += 8)
            {
                if (RomData.MMFileList[swamp_spider_house_fid].Data[b] == 0x15 &&
                    RomData.MMFileList[swamp_spider_house_fid].Data[b + 0x7] == 0x3B)
                {
                    RomData.MMFileList[swamp_spider_house_fid].Data[b + 0x7] = replacement_slot;
                    break;
                }
            }

            int ocean_spider_house_fid = 1291; // taken from ultimate MM spreadsheet

            RomUtils.CheckCompressed(ocean_spider_house_fid);
            for (int b = 0; b < 0x10 * 70; b += 8)
            {
                if (RomData.MMFileList[ocean_spider_house_fid].Data[b] == 0x15 &&
                    RomData.MMFileList[ocean_spider_house_fid].Data[b + 0x7] == 0x3B)
                {
                    RomData.MMFileList[ocean_spider_house_fid].Data[b + 0x7] = replacement_slot;
                    break;
                }
            }


            SequenceInfo new_music_slot = new SequenceInfo
            {
                Name     = "mm-spiderhouse-replacement",
                MM_seq   = replacement_slot,
                Replaces = replacement_slot,
                Type     = new List <int> {
                    2
                },
                Instrument = 3
            };

            RomData.TargetSequences.Add(new_music_slot);
        }
Пример #5
0
        public static void RebuildAudioBank(List <InstrumentSetInfo> InstrumentSetList)
        {
            // get index for the old audiobank, we're putting it back int the same spot but letting it expand into audioseq's spot, because the later is no longer there
            int f = RomUtils.GetFileIndexForWriting(Addresses.AudiobankTable);
            // the DMA table doesn't point directly to the table on the rom, its part of a larger yaz0 file, we have to use an offset to get the address in the file
            int audiobank_table_adjusted_addr = Addresses.AudiobankTable - RomData.MMFileList[RomUtils.GetFileIndexForWriting(Addresses.AudiobankTable)].Addr;

            int current_audiobank_addr = 0;

            byte[] new_audiobank = new byte[0];

            // for each bank, concat onto the new bank byte object, update the table to match the new instrument sets
            for (int inst_set_num = 0; inst_set_num <= 0x28; ++inst_set_num)
            {
                InstrumentSetInfo current_bank = InstrumentSetList[inst_set_num];   // not sure lists are sequential in C#
                int bank_len = current_bank.BankBinary.Length;
                new_audiobank = new_audiobank.Concat(current_bank.BankBinary).ToArray();

                // update address of the bank in the table
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16]     = (byte)((current_audiobank_addr & 0xFF000000) >> 24);
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16 + 1] = (byte)((current_audiobank_addr & 0xFF0000) >> 16);
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16 + 2] = (byte)((current_audiobank_addr & 0xFF00) >> 8);
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16 + 3] = (byte)(current_audiobank_addr & 0xFF);

                // adjust the address for the next sequence to use
                current_audiobank_addr += bank_len;
                int remainder = bank_len % 16;
                if (remainder > 0)                                                              // in the event the user made an audiobank instrument set that isn't padded
                {
                    new_audiobank = new_audiobank.Concat(new byte[remainder + 0x10]).ToArray(); // padding with a spare 16 byte line sounds cheap enough to try
                    Debug.WriteLine("Bank " + inst_set_num + " wasn't padded to 16 bytes:" + bank_len.ToString("X"));
                    current_audiobank_addr += remainder;
                }

                // update length of the bank in the table
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16 + 4] = (byte)((bank_len & 0xFF000000) >> 24);
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16 + 5] = (byte)((bank_len & 0xFF0000) >> 16);
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16 + 6] = (byte)((bank_len & 0xFF00) >> 8);
                RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + inst_set_num * 16 + 7] = (byte)(bank_len & 0xFF);

                // update metadata of the bank in the table
                for (int meta_iter = 0; meta_iter < 8; ++meta_iter)
                {
                    RomData.MMFileList[f].Data[audiobank_table_adjusted_addr + (inst_set_num * 16) + 8 + meta_iter] = current_bank.BankMetaData[meta_iter];
                }
            }

            // write audioseq as a new file
            f = RomUtils.GetFileIndexForWriting(Addresses.Audiobank);
            RomData.MMFileList[f].Data = new_audiobank;
        }
Пример #6
0
        public static void ApplyHack(string path, string name)
        {
            BinaryReader hack_file = new BinaryReader(File.Open(Path.Combine(path, name), FileMode.Open));
            int          hack_len  = (int)hack_file.BaseStream.Length;

            byte[] hack_content = new byte[hack_len];
            hack_file.Read(hack_content, 0, hack_len);
            hack_file.Close();
            if (name.EndsWith("title-screen"))
            {
                Random R   = new Random();
                int    rot = R.Next(360);
                Color  l;
                float  h;
                for (int i = 0; i < 144 * 64; i++)
                {
                    int p = (i * 4) + 8;
                    l  = Color.FromArgb(hack_content[p + 3], hack_content[p], hack_content[p + 1], hack_content[p + 2]);
                    h  = l.GetHue();
                    h += rot;
                    h %= 360f;
                    l  = ColorUtils.FromAHSB(l.A, h, l.GetSaturation(), l.GetBrightness());
                    hack_content[p]     = l.R;
                    hack_content[p + 1] = l.G;
                    hack_content[p + 2] = l.B;
                    hack_content[p + 3] = l.A;
                }
                l  = Color.FromArgb(hack_content[0x1FE72], hack_content[0x1FE73], hack_content[0x1FE76]);
                h  = l.GetHue();
                h += rot;
                h %= 360f;
                l  = ColorUtils.FromAHSB(255, h, l.GetSaturation(), l.GetBrightness());
                hack_content[0x1FE72] = l.R;
                hack_content[0x1FE73] = l.G;
                hack_content[0x1FE76] = l.B;
            }
            int addr = 0;

            while (hack_content[addr] != 0xFF)
            {
                //Debug.WriteLine(addr.ToString("X4"));
                uint dest = ReadWriteUtils.Arr_ReadU32(hack_content, addr);
                addr += 4;
                uint len = ReadWriteUtils.Arr_ReadU32(hack_content, addr);
                addr += 4;
                int f = RomUtils.GetFileIndexForWriting((int)dest);
                dest -= (uint)RomData.MMFileList[f].Addr;
                ReadWriteUtils.Arr_Insert(hack_content, addr, (int)len, RomData.MMFileList[f].Data, (int)dest);
                addr += (int)len;
            }
        }
Пример #7
0
        public static byte[] GetObjectData(int objectIndex)
        {
            var objectTableFileIndex = RomUtils.GetFileIndexForWriting(OBJECT_TABLE);
            var baseAddress          = OBJECT_TABLE - RomData.MMFileList[objectTableFileIndex].Addr;
            var objectAddress        = ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[objectTableFileIndex].Data, baseAddress + (objectIndex * 8));
            var objectFileIndex      = RomData.MMFileList.FindIndex(f => f.Addr == objectAddress);

            if (objectFileIndex == -1)
            {
                return(null);
            }
            RomUtils.CheckCompressed(objectFileIndex);
            return(RomData.MMFileList[objectFileIndex].Data);
        }
Пример #8
0
 public static void UpdateFormTunics(List <int[]> addresses, Color targetColor)
 {
     for (int i = 0; i < addresses.Count; i++)
     {
         for (int j = 0; j < addresses[i].Length; j++)
         {
             int     fileInRom     = RomUtils.GetFileIndexForWriting(addresses[i][j]);
             int     addressInFile = addresses[i][j] - RomData.MMFileList[fileInRom].Addr;
             Color[] colorArray    = ReadColours(fileInRom, addressInFile, paletteSize[i]);
             colorArray = ShiftHue(colorArray, targetColor, paletteSize[i], isZora[i], isGradientImage[i], isFierceDeity[i]);
             WriteColours(fileInRom, addressInFile, paletteSize[i], colorArray);
         }
     }
 }
Пример #9
0
 public static void UpdateFormTunics(List <int[]> addresses, Color target)
 {
     for (int i = 0; i < addresses.Count; i++)
     {
         for (int j = 0; j < addresses[i].Length; j++)
         {
             int     f = RomUtils.GetFileIndexForWriting(addresses[i][j]);
             int     a = addresses[i][j] - RomData.MMFileList[f].Addr;
             Color[] c = ReadColours(f, a, sizes[i]);
             c = ShiftHue(c, target, sizes[i], zora[i], grad[i], fd[i]);
             WriteColours(f, a, sizes[i], c);
         }
     }
 }
Пример #10
0
        public static void RebuildAudioBank(List <InstrumentSetInfo> InstrumentSetList)
        {
            // get index for the old audiobank, we're putting it back in the same spot but letting it expand into audioseq's spot, which was moved to the end
            int fid = RomUtils.GetFileIndexForWriting(Addresses.AudiobankTable);
            // the DMA table doesn't point directly to the indextable on the rom, its part of a larger yaz0 file, we have to use an offset to get the address in the file
            int audiobankIndexOffset = Addresses.AudiobankTable - RomData.MMFileList[RomUtils.GetFileIndexForWriting(Addresses.AudiobankTable)].Addr;

            int audiobankBankOffset = 0;
            var audiobankData       = new byte[0];

            // for each bank, concat onto the new bank byte object, update the table to match the new instrument sets
            for (int audiobankIndex = 0; audiobankIndex <= 0x28; ++audiobankIndex)
            {
                var currentBank = InstrumentSetList[audiobankIndex];
                audiobankData = audiobankData.Concat(currentBank.BankBinary).ToArray();

                // update address of the bank in the index table
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 0] = (byte)((audiobankBankOffset & 0xFF000000) >> 24);
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 1] = (byte)((audiobankBankOffset & 0xFF0000) >> 16);
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 2] = (byte)((audiobankBankOffset & 0xFF00) >> 8);
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 3] = (byte)(audiobankBankOffset & 0xFF);

                // update length of the bank in the table
                int currentBankLength = currentBank.BankBinary.Length;
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 4] = (byte)((currentBankLength & 0xFF000000) >> 24);
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 5] = (byte)((currentBankLength & 0xFF0000) >> 16);
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 6] = (byte)((currentBankLength & 0xFF00) >> 8);
                RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 7] = (byte)(currentBankLength & 0xFF);

                // update metadata of the bank in the table
                for (int metadataIter = 0; metadataIter < 8; ++metadataIter)
                {
                    RomData.MMFileList[fid].Data[audiobankIndexOffset + (audiobankIndex * 16) + 8 + metadataIter] = currentBank.BankMetaData[metadataIter];
                }

                // adjust the address for the next bank to use
                audiobankBankOffset += currentBankLength;
                int paddingRemainder = currentBankLength % 0x10;
                if (paddingRemainder > 0)                                                                     // in the event the user made an audiobank instrument set that isn't padded
                {
                    audiobankData        = audiobankData.Concat(new byte[paddingRemainder + 0x10]).ToArray(); // padding with a spare 16 byte line sounds cheap enough to try
                    audiobankBankOffset += paddingRemainder;
                }
            }

            // write new audiobank back to file
            RomData.MMFileList[RomUtils.GetFileIndexForWriting(Addresses.Audiobank)].Data = audiobankData;
        }
Пример #11
0
 public static void WriteROMAddr(int[] Addr, byte[] data)
 {
     for (int i = 0; i < Addr.Length; i++)
     {
         int    var   = (int)(Addr[i] & 0xF0000000) >> 28;
         int    rAddr = Addr[i] & 0xFFFFFFF;
         byte[] rdata = data;
         if (var == 1)
         {
             rdata[0] += 0xA;
             rdata[1] -= 0x70;
         }
         int f    = RomUtils.GetFileIndexForWriting(rAddr);
         int dest = rAddr - RomData.MMFileList[f].Addr;
         Arr_Insert(rdata, 0, rdata.Length, RomData.MMFileList[f].Data, dest);
     }
 }
Пример #12
0
        public static void ApplyHack(byte[] hack_content)
        {
            int addr = 0;

            while (hack_content[addr] != 0xFF)
            {
                //Debug.WriteLine(addr.ToString("X4"));
                uint dest = ReadWriteUtils.Arr_ReadU32(hack_content, addr);
                addr += 4;
                uint len = ReadWriteUtils.Arr_ReadU32(hack_content, addr);
                addr += 4;
                int f = RomUtils.GetFileIndexForWriting((int)dest);
                dest -= (uint)RomData.MMFileList[f].Addr;
                ReadWriteUtils.Arr_Insert(hack_content, addr, (int)len, RomData.MMFileList[f].Data, (int)dest);
                addr += (int)len;
            }
        }
Пример #13
0
        public static void WriteNewSoundSamples(List <InstrumentSetInfo> InstrumentSetList)
        {
            /// Writing all of our new samples in a single file at the end
            //  in the event we run out of MMFile DMA indexes: These files dont need to be a hard file in the filesystem
            //  they can be placed anywhere after the soundbank starting address on rom, instrument sample lookup doesnt use file system
            //  adding to the file system is just useful for shifting in BuildROM()

            // issue: we don't know right now where the samples will be written to, because BuildRom will shift the files
            //  for now we write samples, after audiobank/soundbank/samples are written, we'll update audiobank pointers
            // save extra soundsamples fid, and the samples with their data, for later (UpdateBankInstrumentPointers())
            int fid = RomData.SamplesFileID = RomUtils.AppendFile(new byte[0x0]);

            RomData.ListOfSamples = new List <SequenceSoundSampleBinaryData>();

            // for each custom instrument set that needs a custom sample
            foreach (InstrumentSetInfo instrumentSet in InstrumentSetList)
            {
                if (instrumentSet.InstrumentSamples != null && instrumentSet.InstrumentSamples.Count > 0)
                {
                    foreach (SequenceSoundSampleBinaryData sample in instrumentSet.InstrumentSamples)
                    {
                        // test if sample was already added by another song (OOT instruments for instance)
                        var previouslyWrittenSample = RomData.ListOfSamples.Find(u => sample.Hash == u.Hash);
                        if (previouslyWrittenSample == null) // if sample not already written once before
                        {
                            // get the rom addr of our new file, our file will start at the end of the last file
                            sample.Addr = (uint)RomData.MMFileList[fid].Data.Length;
                            // concat our sample to sample collection file
                            RomData.MMFileList[fid].Data = RomData.MMFileList[fid].Data.Concat(sample.BinaryData).ToArray();
                            // I don't know if samples need to be padded to 0x10 like sequences but might as well
                            int paddingRemainder = RomData.MMFileList[fid].Data.Length % 0x10;
                            if (paddingRemainder > 0)
                            {
                                RomData.MMFileList[fid].Data = RomData.MMFileList[fid].Data.Concat(new byte[paddingRemainder]).ToArray();
                            }
                            RomData.ListOfSamples.Add(sample);
                        }
                        else // get address of previously used sample
                        {
                            sample.Addr = previouslyWrittenSample.Addr;
                        }
                    }
                }
            }
        }
Пример #14
0
        public static void ReplaceGetItemTable()
        {
            ResourceUtils.ApplyHack(Resources.mods.replace_gi_table);
            int last_file = RomData.MMFileList.Count - 1;

            GET_ITEM_TABLE = RomUtils.AddNewFile(Resources.mods.gi_table);
            ReadWriteUtils.WriteToROM(0xBDAEAC, (uint)last_file + 1);
            ResourceUtils.ApplyHack(Resources.mods.update_chests);
            RomUtils.AddNewFile(Resources.mods.chest_table);
            ReadWriteUtils.WriteToROM(0xBDAEA8, (uint)last_file + 2);
            ResourceUtils.ApplyHack(Resources.mods.standing_hearts);
            ResourceUtils.ApplyHack(Resources.mods.fix_item_checks);
            SceneUtils.ResetSceneFlagMask();
            SceneUtils.UpdateSceneFlagMask(0x5B); // red potion
            SceneUtils.UpdateSceneFlagMask(0x91); // chateau romani
            SceneUtils.UpdateSceneFlagMask(0x92); // milk
            SceneUtils.UpdateSceneFlagMask(0x93); // gold dust
        }
Пример #15
0
        private static void InitGetBottleList()
        {
            RomData.BottleList = new Dictionary <int, BottleCatchEntry>();
            int f        = RomUtils.GetFileIndexForWriting(BOTTLE_CATCH_TABLE);
            int baseaddr = BOTTLE_CATCH_TABLE - RomData.MMFileList[f].Addr;
            var fileData = RomData.MMFileList[f].Data;

            foreach (var getBottleItemIndex in ItemUtils.AllGetBottleItemIndices())
            {
                int offset = getBottleItemIndex * 6 + baseaddr;
                RomData.BottleList[getBottleItemIndex] = new BottleCatchEntry
                {
                    ItemGained = fileData[offset + 3],
                    Index      = fileData[offset + 4],
                    Message    = fileData[offset + 5]
                };
            }
        }
Пример #16
0
        /// <summary>
        /// Get image data for the 4 stray fairy icons.
        /// </summary>
        /// <returns>Array of image bytes.</returns>
        public static byte[][] GetStrayFairyIcons()
        {
            // Stray Fairy icons start at: 0xA0A000 + 0x1B80
            RomUtils.CheckCompressed(11);
            var fileData = RomData.MMFileList[11].Data;

            // Extract HUD icon for Stray Fairy icons.
            var fairies = new List <byte[]>(4);

            for (int i = 0; i < 4; i++)
            {
                var imageData = new byte[0xC00];
                var offset    = 0x1B80 + (imageData.Length * i);
                Buffer.BlockCopy(fileData, offset, imageData, 0, imageData.Length);
                fairies.Add(imageData);
            }

            return(fairies.ToArray());
        }
Пример #17
0
        public static void ReplaceGetItemTable()
        {
            ResourceUtils.ApplyHack(Values.ModsDirectory, "replace-gi-table");
            int last_file = RomData.MMFileList.Count - 1;

            GET_ITEM_TABLE = RomUtils.AddNewFile(Values.ModsDirectory, "gi-table");
            ReadWriteUtils.WriteToROM(0xBDAEAC, (uint)last_file + 1);
            ResourceUtils.ApplyHack(Values.ModsDirectory, "update-chests");
            RomUtils.AddNewFile(Values.ModsDirectory, "chest-table");
            ReadWriteUtils.WriteToROM(0xBDAEA8, (uint)last_file + 2);
            ResourceUtils.ApplyHack(Values.ModsDirectory, "standing-hearts");
            ResourceUtils.ApplyHack(Values.ModsDirectory, "fix-item-checks");
            cycle_repeat = 0xC72DF4;
            SceneUtils.ResetSceneFlagMask();
            SceneUtils.UpdateSceneFlagMask(0x5B); // red potion
            SceneUtils.UpdateSceneFlagMask(0x91); // chateau romani
            SceneUtils.UpdateSceneFlagMask(0x92); // milk
            SceneUtils.UpdateSceneFlagMask(0x93); // gold dust
        }
Пример #18
0
        public static void UpdateSceneFlagMask(int num)
        {
            int offset = num >> 3;
            int mod    = offset % 16;

            if (mod < 4)
            {
                offset += 8;
            }
            else if (mod < 12)
            {
                offset -= 4;
            }

            int bit  = 1 << (num & 7);
            int f    = RomUtils.GetFileIndexForWriting(SCENE_FLAG_MASKS);
            int addr = SCENE_FLAG_MASKS - RomData.MMFileList[f].Addr + offset;

            RomData.MMFileList[f].Data[addr] |= (byte)bit;
        }
Пример #19
0
        private static void InitGetItemList()
        {
            RomData.GetItemList = new Dictionary <int, GetItemEntry>();
            int f        = RomUtils.GetFileIndexForWriting(GET_ITEM_TABLE);
            var fileData = RomData.MMFileList[f].Data;

            for (var i = 0; i < fileData.Length; i += 8)
            {
                var getItemIndex = (i / 8) + 1;
                RomData.GetItemList[getItemIndex] = new GetItemEntry
                {
                    ItemGained = fileData[i],
                    Flag       = fileData[i + 1],
                    Index      = fileData[i + 2],
                    Type       = fileData[i + 3],
                    Message    = (short)((fileData[i + 4] << 8) | fileData[i + 5]),
                    Object     = (short)((fileData[i + 6] << 8) | fileData[i + 7])
                };
            }
        }
Пример #20
0
        public static void WriteNewBottle(Item location, Item item)
        {
            System.Diagnostics.Debug.WriteLine($"Writing {item.Name()} --> {location.Location()}");

            int f        = RomUtils.GetFileIndexForWriting(BOTTLE_CATCH_TABLE);
            int baseaddr = BOTTLE_CATCH_TABLE - RomData.MMFileList[f].Addr;
            var fileData = RomData.MMFileList[f].Data;

            foreach (var index in location.GetBottleItemIndices())
            {
                var offset    = index * 6 + baseaddr;
                var newBottle = RomData.BottleList[item.GetBottleItemIndices()[0]];
                var data      = new byte[]
                {
                    newBottle.ItemGained,
                    newBottle.Index,
                    newBottle.Message,
                };
                ReadWriteUtils.Arr_Insert(data, 0, data.Length, fileData, offset + 3);
            }
        }
Пример #21
0
        private static void InitGetItemList()
        {
            RomData.GetItemList = new Dictionary <int, GetItemEntry>();
            int f        = RomUtils.GetFileIndexForWriting(GET_ITEM_TABLE);
            int baseaddr = GET_ITEM_TABLE - RomData.MMFileList[f].Addr;
            var fileData = RomData.MMFileList[f].Data;

            foreach (var getItemIndex in ItemUtils.AllGetItemIndices())
            {
                int offset = (getItemIndex - 1) * 8 + baseaddr;
                RomData.GetItemList[getItemIndex] = new GetItemEntry
                {
                    ItemGained = fileData[offset],
                    Flag       = fileData[offset + 1],
                    Index      = fileData[offset + 2],
                    Type       = fileData[offset + 3],
                    Message    = (short)((fileData[offset + 4] << 8) | fileData[offset + 5]),
                    Object     = (short)((fileData[offset + 6] << 8) | fileData[offset + 7])
                };
            }
        }
Пример #22
0
 public static void GetMaps()
 {
     foreach (var scene in RomData.SceneList)
     {
         int f = scene.File;
         RomUtils.CheckCompressed(f);
         int j = 0;
         while (true)
         {
             byte cmd = RomData.MMFileList[f].Data[j];
             if (cmd == 0x04)
             {
                 byte mapcount = RomData.MMFileList[f].Data[j + 1];
                 int  mapsaddr = (int)ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, j + 4) & 0xFFFFFF;
                 for (int k = 0; k < mapcount; k++)
                 {
                     Map m = new Map();
                     m.File = RomUtils.AddrToFile((int)ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, mapsaddr));
                     scene.Maps.Add(m);
                     mapsaddr += 8;
                 }
                 break;
             }
             if (cmd == 0x14)
             {
                 break;
             }
             j += 8;
         }
         CheckHeaderForExits(f, 0, scene);
         if (scene.Number == 108) // avoid modifying unused setup in East Clock Town. doesn't seem to actually affect anything in-game, but best not to touch it.
         {
             scene.Setups.RemoveAt(2);
         }
     }
 }
Пример #23
0
        public static void ReadSceneTable()
        {
            RomData.SceneList = new List <Scene>();
            int f           = RomUtils.GetFileIndexForWriting(SCENE_TABLE);
            int _SceneTable = SCENE_TABLE - RomData.MMFileList[f].Addr;
            int i           = 0;

            while (true)
            {
                Scene s     = new Scene();
                uint  saddr = ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, _SceneTable + i);
                if (saddr > 0x4000000)
                {
                    break;
                }
                if (saddr != 0)
                {
                    s.File   = RomUtils.AddrToFile((int)saddr);
                    s.Number = i >> 4;
                    RomData.SceneList.Add(s);
                }
                i += 16;
            }
        }
Пример #24
0
        public static void WriteNewItem(ItemObject itemObject, List <MessageEntry> newMessages, GameplaySettings settings, ChestTypeAttribute.ChestType?overrideChestType)
        {
            var item     = itemObject.Item;
            var location = itemObject.NewLocation.Value;

            System.Diagnostics.Debug.WriteLine($"Writing {item.Name()} --> {location.Location()}");

            int f            = RomUtils.GetFileIndexForWriting(GET_ITEM_TABLE);
            int baseaddr     = GET_ITEM_TABLE - RomData.MMFileList[f].Addr;
            var getItemIndex = location.GetItemIndex().Value;
            int offset       = (getItemIndex - 1) * 8 + baseaddr;
            var fileData     = RomData.MMFileList[f].Data;

            GetItemEntry newItem;

            if (item.IsExclusiveItem())
            {
                newItem = item.ExclusiveItemEntry();
            }
            else
            {
                newItem = RomData.GetItemList[item.GetItemIndex().Value];
            }

            var data = new byte[]
            {
                newItem.ItemGained,
                newItem.Flag,
                newItem.Index,
                newItem.Type,
                (byte)(newItem.Message >> 8),
                (byte)(newItem.Message & 0xFF),
                (byte)(newItem.Object >> 8),
                (byte)(newItem.Object & 0xFF),
            };

            ReadWriteUtils.Arr_Insert(data, 0, data.Length, fileData, offset);

            // todo use Logic Editor to handle which locations should be repeatable and which shouldn't.
            var isCycleRepeatable = item.IsCycleRepeatable();

            if (item.Name().Contains("Rupee") && location.IsRupeeRepeatable())
            {
                isCycleRepeatable = true;
            }
            if (item.ToString().StartsWith("Trade") && settings.QuestItemStorage)
            {
                isCycleRepeatable = false;
            }
            if (isCycleRepeatable)
            {
                settings.AsmOptions.MMRConfig.CycleRepeatableLocations.Add(getItemIndex);
            }

            var isRepeatable = item.IsRepeatable() || (!settings.PreventDowngrades && item.IsDowngradable());

            if (settings.ProgressiveUpgrades && item.HasAttribute <ProgressiveAttribute>())
            {
                isRepeatable = false;
            }
            if (!isRepeatable)
            {
                SceneUtils.UpdateSceneFlagMask(getItemIndex);
            }

            if (settings.UpdateChests)
            {
                UpdateChest(location, item, overrideChestType);
            }

            if (settings.UpdateShopAppearance)
            {
                UpdateShop(itemObject, newMessages);
            }

            if (location != item)
            {
                if (location == Item.StartingSword)
                {
                    ResourceUtils.ApplyHack(Resources.mods.fix_sword_song_of_time);
                }

                if (location == Item.MundaneItemSeahorse)
                {
                    ResourceUtils.ApplyHack(Resources.mods.fix_fisherman);
                }

                if (location == Item.MaskFierceDeity)
                {
                    ResourceUtils.ApplyHack(Resources.mods.fix_fd_mask_reset);
                }
            }
        }
Пример #25
0
        public static int AddNewFile(byte[] content)
        {
            int index = RomUtils.AppendFile(content);

            return(RomData.MMFileList[index].Addr);
        }
Пример #26
0
 /// <summary>
 /// Get the <see cref="MMFile"/> at a <see cref="FileIndex"/>.
 /// </summary>
 /// <param name="index">File index.</param>
 /// <returns></returns>
 static MMFile GetFile(FileIndex index)
 {
     RomUtils.CheckCompressed((int)index);
     return(RomData.MMFileList[(int)index]);
 }
Пример #27
0
        public static void ReenableNightBGM()
        {
            // summary: there is a scene header which has a single byte that determines what plays at night, setting to 13 re-enables BGM at night

            // since scene table is only read previously on enemizer, if not loaded we have to load now
            if (RomData.SceneList == null)
            {
                ReadSceneTable();
            }

            // TODO since this is static, it can be moved
            var TargetSceneEnums = new GameObjects.Scene[]
            {
                GameObjects.Scene.TerminaField,
                GameObjects.Scene.RoadToSouthernSwamp,
                GameObjects.Scene.SouthernSwamp,
                GameObjects.Scene.SouthernSwampClear,
                GameObjects.Scene.PathToMountainVillage,
                GameObjects.Scene.MountainVillage,
                GameObjects.Scene.MountainVillageSpring,
                GameObjects.Scene.TwinIslands,
                GameObjects.Scene.TwinIslandsSpring,
                GameObjects.Scene.GoronRacetrack,
                GameObjects.Scene.GoronVillage,
                GameObjects.Scene.GoronVillageSpring,
                GameObjects.Scene.PathToSnowhead,
                GameObjects.Scene.Snowhead,
                GameObjects.Scene.MilkRoad,
                GameObjects.Scene.GreatBayCoast,
                GameObjects.Scene.PinnacleRock,
                GameObjects.Scene.ZoraCape,
                GameObjects.Scene.WaterfallRapids,
                GameObjects.Scene.RoadToIkana,
                GameObjects.Scene.IkanaCanyon,
                GameObjects.Scene.EastClockTown,
                GameObjects.Scene.WestClockTown,
                GameObjects.Scene.NorthClockTown,
                GameObjects.Scene.SouthClockTown,
                GameObjects.Scene.LaundryPool,
                GameObjects.Scene.Woodfall,
            }.ToList();

            foreach (var SceneEnum in TargetSceneEnums)
            {
                ReenableNightBGMSingle(RomData.SceneList.Find(u => u.Number == SceneEnum.Id()).File);
            }

            // Kamaro the dancing ghost in Termina Field breaks night music
            //   he calls a function that sets an unknown actor flag unk39 & 20, he calls this function per frame from multiple places
            // if we nop it his music never plays, and might music is never interupted by him
            var kamaroFID = 593;

            RomUtils.CheckCompressed(kamaroFID);
            var kamaroData = RomData.MMFileList[kamaroFID].Data;

            // null function call to func_800B9084 -> NOP
            ReadWriteUtils.Arr_WriteU32(kamaroData, 0x618, 0x00000000);

            // Sakon the Bomb Bag theif breaks night music
            //   on first night, after he's supposed to have stolen the bag
            //   his actor will spawn, check the time, and self-destroy, and take out BGM with it
            // if we nop that kill music command it will stop him from stopping BGM
            var sakonFID = 526;

            RomUtils.CheckCompressed(sakonFID);
            var sakonData = RomData.MMFileList[sakonFID].Data;

            // null function call to Audio_QueueSeqCmd -> NOP
            ReadWriteUtils.Arr_WriteU32(sakonData, 0x3A0C, 0x00000000);
        }
Пример #28
0
        // gets passed RomData.SequenceList in Builder.cs::WriteAudioSeq
        public static void RebuildAudioSeq(List <SequenceInfo> SequenceList, OutputSettings _settings)
        {
            // spoiler log output DEBUG
            StringBuilder log = new StringBuilder();

            void WriteOutput(string str)
            {
                Debug.WriteLine(str); // we still want debug output though
                log.AppendLine(str);
            }

            List <MMSequence> OldSeq = new List <MMSequence>();
            int f     = RomUtils.GetFileIndexForWriting(Addresses.SeqTable);
            int basea = RomData.MMFileList[f].Addr;

            for (int i = 0; i < 128; i++)
            {
                MMSequence entry = new MMSequence();
                if (i == 0x1E) // intro music when link gets ambushed
                {
                    entry.Addr = 2;
                    OldSeq.Add(entry);
                    continue;
                }

                int entryaddr = Addresses.SeqTable + (i * 16);
                entry.Addr = (int)ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, entryaddr - basea);
                var size = (int)ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, (entryaddr - basea) + 4);
                if (size > 0)
                {
                    entry.Data = new byte[size];
                    Array.Copy(RomData.MMFileList[4].Data, entry.Addr, entry.Data, 0, entry.Size);
                }
                else
                {
                    int j = SequenceList.FindIndex(u => u.Replaces == i);
                    if (j != -1)
                    {
                        if ((entry.Addr > 0) && (entry.Addr < 128))
                        {
                            if (SequenceList[j].Replaces != 0x28) // 28 (fairy fountain)
                            {
                                SequenceList[j].Replaces = entry.Addr;
                            }
                            else
                            {
                                entry.Data = OldSeq[0x18].Data;
                            }
                        }
                    }
                }
                OldSeq.Add(entry);
            }

            List <MMSequence> NewSeq = new List <MMSequence>();
            int addr = 0;

            byte[] NewAudioSeq = new byte[0];
            for (int i = 0; i < 128; i++)
            {
                MMSequence newentry = new MMSequence();
                if (OldSeq[i].Size == 0)
                {
                    newentry.Addr = OldSeq[i].Addr;
                }
                else
                {
                    newentry.Addr = addr;
                }

                if (SequenceList.FindAll(u => u.Replaces == i).Count > 1)
                {
                    WriteOutput("Error: Slot " + i.ToString("X") + " has multiple songs pointing at it!");
                }

                int p = RomData.PointerizedSequences.FindIndex(u => u.PreviousSlot == i);
                int j = SequenceList.FindIndex(u => u.Replaces == i);
                if (p != -1)
                {
                    // found song we want to pointerize
                    newentry.Addr = RomData.PointerizedSequences[p].Replaces;
                }
                else if (j != -1)
                {
                    // new song to replace old slot found
                    if (SequenceList[j].MM_seq != -1)
                    {
                        newentry.Data = OldSeq[SequenceList[j].MM_seq].Data;
                        WriteOutput("Slot " + i.ToString("X2") + " -> " + SequenceList[j].Name);
                    }
                    else if (SequenceList[j].SequenceBinaryList != null && SequenceList[j].SequenceBinaryList.Count > 0)
                    {
                        if (SequenceList[j].SequenceBinaryList.Count > 1)
                        {
                            WriteOutput("Warning: writing song with multiple sequence/bank combos, selecting first available");
                        }
                        newentry.Data = SequenceList[j].SequenceBinaryList[0].SequenceBinary;
                        WriteOutput("Slot " + i.ToString("X2") + " := " + SequenceList[j].Name + " *");
                    }
                    else // non mm, load file and add
                    {
                        byte[] data;
                        if (File.Exists(SequenceList[j].Filename))
                        {
                            using (var reader = new BinaryReader(File.OpenRead(SequenceList[j].Filename)))
                            {
                                data = new byte[(int)reader.BaseStream.Length];
                                reader.Read(data, 0, data.Length);
                            }
                        }
                        else if (SequenceList[j].Name == nameof(Properties.Resources.mmr_f_sot))
                        {
                            data = Properties.Resources.mmr_f_sot;
                        }
                        else
                        {
                            throw new Exception("Music not found as file or built-in resource." + SequenceList[j].Filename);
                        }

                        // I think this checks if the sequence type is correct for MM
                        //  because DB ripped sequences from SF64/SM64/MK64 without modifying them
                        if (data[1] != 0x20)
                        {
                            data[1] = 0x20;
                        }

                        newentry.Data = data;
                        WriteOutput("Slot " + i.ToString("X2") + " := " + SequenceList[j].Name);
                    }
                }
                else // not found, song wasn't touched by rando, just transfer over
                {
                    newentry.Data = OldSeq[i].Data;
                }

                // if the sequence is not padded to 16 bytes, the DMA fails
                //  music can stop from playing and on hardware it will just straight crash
                var Padding = 0x10 - newentry.Size % 0x10;
                if (Padding != 0x10)
                {
                    newentry.Data = newentry.Data.Concat(new byte[Padding]).ToArray();
                }

                NewSeq.Add(newentry);
                // TODO is there not a better way to write this?
                if (newentry.Data != null)
                {
                    NewAudioSeq = NewAudioSeq.Concat(newentry.Data).ToArray();
                }

                addr += newentry.Size;
            }

            // discovered when MM-only music was fixed, if the audioseq is left in it's old spot
            // audio quality is garbage, sounds like static
            //if (addr > (RomData.MMFileList[4].End - RomData.MMFileList[4].Addr))
            //else
            //RomData.MMFileList[4].Data = NewAudioSeq;

            int index = RomUtils.AppendFile(NewAudioSeq);

            ResourceUtils.ApplyHack(Values.ModsDirectory, "reloc-audio");
            RelocateSeq(index);
            RomData.MMFileList[4].Data     = new byte[0];
            RomData.MMFileList[4].Cmp_Addr = -1;
            RomData.MMFileList[4].Cmp_End  = -1;

            //update sequence index pointer table
            f = RomUtils.GetFileIndexForWriting(Addresses.SeqTable);
            for (int i = 0; i < 128; i++)
            {
                ReadWriteUtils.Arr_WriteU32(RomData.MMFileList[f].Data, (Addresses.SeqTable + (i * 16)) - basea, (uint)NewSeq[i].Addr);
                ReadWriteUtils.Arr_WriteU32(RomData.MMFileList[f].Data, 4 + (Addresses.SeqTable + (i * 16)) - basea, (uint)NewSeq[i].Size);
            }

            //update inst sets used by each new seq
            // this is NOT the audiobank, its the complementary instrument set value for each sequence
            //   IE, sequence 7 uses instrument set "10", we replaced it with sequnece ae which needs bank "23"
            f     = RomUtils.GetFileIndexForWriting(Addresses.InstSetMap);
            basea = RomData.MMFileList[f].Addr;
            for (int i = 0; i < 128; i++)
            {
                // huh? paddr? pointer? padding?
                int paddr = (Addresses.InstSetMap - basea) + (i * 2) + 2;

                int j = -1;
                if (NewSeq[i].Size == 0) // pointer, we need to copy the instrumnet set from the destination
                {
                    j = SequenceList.FindIndex(u => u.Replaces == NewSeq[i].Addr);
                }
                else
                {
                    j = SequenceList.FindIndex(u => u.Replaces == i);
                }

                if (j != -1)
                {
                    RomData.MMFileList[f].Data[paddr] = (byte)SequenceList[j].Instrument;
                }
            }

            //// DEBUG spoiler log output
            //String dir = Path.GetDirectoryName(_settings.OutputROMFilename);
            //String path = $"{Path.GetFileNameWithoutExtension(_settings.OutputROMFilename)}";
            //// spoiler log should already be written by the time we reach this far
            //if (File.Exists(Path.Combine(dir, path + "_SpoilerLog.txt")))
            //    path += "_SpoilerLog.txt";
            //else // TODO add HTML log compatibility
            //    path += "_SongLog.txt";

            //using (StreamWriter sw = new StreamWriter(Path.Combine(dir, path), append: true))
            //{
            //    sw.WriteLine(""); // spacer
            //    sw.Write(log);
            //}
        }
Пример #29
0
        public static void WriteNewItem(Item location, Item item, List <MessageEntry> newMessages, bool updateShop, bool preventDowngrades, bool updateChest, ChestTypeAttribute.ChestType?overrideChestType, bool isExtraStartingItem)
        {
            System.Diagnostics.Debug.WriteLine($"Writing {item.Name()} --> {location.Location()}");

            int f            = RomUtils.GetFileIndexForWriting(GET_ITEM_TABLE);
            int baseaddr     = GET_ITEM_TABLE - RomData.MMFileList[f].Addr;
            var getItemIndex = location.GetItemIndex().Value;
            int offset       = (getItemIndex - 1) * 8 + baseaddr;
            var newItem      = isExtraStartingItem
                ? Items.RecoveryHeart // Warning: this will not work well for starting with Bottle contents (currently impossible), because you'll first have to acquire the Recovery Heart before getting the bottle-less version. Also may interfere with future implementation of progressive upgrades.
                : RomData.GetItemList[item.GetItemIndex().Value];
            var fileData = RomData.MMFileList[f].Data;

            var data = new byte[]
            {
                newItem.ItemGained,
                newItem.Flag,
                newItem.Index,
                newItem.Type,
                (byte)(newItem.Message >> 8),
                (byte)(newItem.Message & 0xFF),
                (byte)(newItem.Object >> 8),
                (byte)(newItem.Object & 0xFF),
            };

            ReadWriteUtils.Arr_Insert(data, 0, data.Length, fileData, offset);

            // todo use Logic Editor to handle which locations should be repeatable and which shouldn't.
            if ((item.IsCycleRepeatable() && location != Item.HeartPieceNotebookMayor) || (item.Name().Contains("Rupee") && location.IsRupeeRepeatable()))
            {
                ReadWriteUtils.WriteToROM(cycle_repeat, (ushort)getItemIndex);
                cycle_repeat       += 2;
                cycle_repeat_count += 2;

                ReadWriteUtils.WriteToROM(cycle_repeat_count_address, cycle_repeat_count);
            }

            var isRepeatable = item.IsRepeatable() || (!preventDowngrades && item.IsDowngradable());

            if (!isRepeatable)
            {
                SceneUtils.UpdateSceneFlagMask(getItemIndex);
            }

            if (item == Item.ItemBottleWitch)
            {
                ReadWriteUtils.WriteToROM(0xB4997E, (ushort)getItemIndex);
                ReadWriteUtils.WriteToROM(0xC72B42, (ushort)getItemIndex);
            }

            if (item == Item.ItemBottleMadameAroma)
            {
                ReadWriteUtils.WriteToROM(0xB4998A, (ushort)getItemIndex);
                ReadWriteUtils.WriteToROM(0xC72B4E, (ushort)getItemIndex);
            }

            if (item == Item.ItemBottleAliens)
            {
                ReadWriteUtils.WriteToROM(0xB49996, (ushort)getItemIndex);
                ReadWriteUtils.WriteToROM(0xC72B5A, (ushort)getItemIndex);
            }

            if (item == Item.ItemBottleGoronRace)
            {
                ReadWriteUtils.WriteToROM(0xB499A2, (ushort)getItemIndex);
                ReadWriteUtils.WriteToROM(0xC72B66, (ushort)getItemIndex);
            }

            if (updateChest)
            {
                UpdateChest(location, item, overrideChestType);
            }

            if (location != item)
            {
                if (updateShop)
                {
                    UpdateShop(location, item, newMessages);
                }

                if (location == Item.StartingSword)
                {
                    ResourceUtils.ApplyHack(Values.ModsDirectory, "fix-sword-song-of-time");
                }

                if (location == Item.MundaneItemSeahorse)
                {
                    ResourceUtils.ApplyHack(Values.ModsDirectory, "fix-fisherman");
                }

                if (location == Item.MaskFierceDeity)
                {
                    ResourceUtils.ApplyHack(Values.ModsDirectory, "fix-fd-mask-reset");
                }
            }
        }
Пример #30
0
        public static void WriteNewItem(ItemObject itemObject, List <MessageEntry> newMessages, GameplaySettings settings, ChestTypeAttribute.ChestType?overrideChestType, MessageTable messageTable, ExtendedObjects extendedObjects)
        {
            var item     = itemObject.Item;
            var location = itemObject.NewLocation.Value;

            System.Diagnostics.Debug.WriteLine($"Writing {item.Name()} --> {location.Location()}");

            if (!itemObject.IsRandomized)
            {
                var indices = location.GetCollectableIndices();
                if (indices.Any())
                {
                    foreach (var collectableIndex in location.GetCollectableIndices())
                    {
                        ReadWriteUtils.Arr_WriteU16(RomData.MMFileList[COLLECTABLE_TABLE_FILE_INDEX].Data, collectableIndex * 2, 0);
                    }
                    return;
                }
            }

            int f            = RomUtils.GetFileIndexForWriting(GET_ITEM_TABLE);
            int baseaddr     = GET_ITEM_TABLE - RomData.MMFileList[f].Addr;
            var getItemIndex = location.GetItemIndex().Value;
            int offset       = (getItemIndex - 1) * 8 + baseaddr;
            var fileData     = RomData.MMFileList[f].Data;

            GetItemEntry newItem;

            if (!itemObject.IsRandomized && location.IsNullableItem())
            {
                newItem = new GetItemEntry();
            }
            else if (item.IsExclusiveItem())
            {
                newItem = item.ExclusiveItemEntry();
            }
            else
            {
                newItem = RomData.GetItemList[item.GetItemIndex().Value];
            }

            // Attempt to resolve extended object Id, which should affect "Exclusive Items" as well.
            var graphics = extendedObjects.ResolveGraphics(newItem);

            if (graphics.HasValue)
            {
                newItem.Object = graphics.Value.objectId;
                newItem.Index  = graphics.Value.graphicId;
            }

            var data = new byte[]
            {
                newItem.ItemGained,
                newItem.Flag,
                newItem.Index,
                newItem.Type,
                (byte)(newItem.Message >> 8),
                (byte)(newItem.Message & 0xFF),
                (byte)(newItem.Object >> 8),
                (byte)(newItem.Object & 0xFF),
            };

            ReadWriteUtils.Arr_Insert(data, 0, data.Length, fileData, offset);

            int?refillGetItemIndex = item switch
            {
                Item.ItemBottleMadameAroma => 0x91,
                Item.ItemBottleAliens => 0x92,
                _ => null,
            };

            if (refillGetItemIndex.HasValue)
            {
                var refillItem     = RomData.GetItemList[refillGetItemIndex.Value];
                var refillGraphics = extendedObjects.ResolveGraphics(refillItem);
                if (refillGraphics.HasValue)
                {
                    refillItem.Object = refillGraphics.Value.objectId;
                    refillItem.Index  = refillGraphics.Value.graphicId;
                }
                var refillData = new byte[]
                {
                    refillItem.ItemGained,
                    refillItem.Flag,
                    refillItem.Index,
                    refillItem.Type,
                    (byte)(refillItem.Message >> 8),
                    (byte)(refillItem.Message & 0xFF),
                    (byte)(refillItem.Object >> 8),
                    (byte)(refillItem.Object & 0xFF),
                };
                var refillOffset = (refillGetItemIndex.Value - 1) * 8 + baseaddr;
                ReadWriteUtils.Arr_Insert(refillData, 0, refillData.Length, fileData, refillOffset);
            }

            if (location.IsRupeeRepeatable())
            {
                settings.AsmOptions.MMRConfig.RupeeRepeatableLocations.Add(getItemIndex);
            }

            var isRepeatable = item.IsRepeatable(settings) || (!settings.PreventDowngrades && item.IsDowngradable());

            if (settings.ProgressiveUpgrades && item.HasAttribute <ProgressiveAttribute>())
            {
                isRepeatable = false;
            }
            if (item.IsReturnable(settings))
            {
                isRepeatable = false;
                settings.AsmOptions.MMRConfig.ItemsToReturnIds.Add(getItemIndex);
            }
            if (!isRepeatable)
            {
                SceneUtils.UpdateSceneFlagMask(getItemIndex);
            }

            if (settings.UpdateChests)
            {
                UpdateChest(location, item, overrideChestType);
            }

            if (settings.UpdateShopAppearance)
            {
                UpdateShop(itemObject, newMessages, messageTable);
            }

            if (itemObject.IsRandomized)
            {
                var hackContentAttributes = location.GetAttributes <HackContentAttribute>();
                if (location == item)
                {
                    hackContentAttributes = hackContentAttributes.Where(h => !h.ApplyOnlyIfItemIsDifferent);
                }
                foreach (var hackContent in hackContentAttributes.Select(h => h.HackContent))
                {
                    ResourceUtils.ApplyHack(hackContent);
                }
            }
        }