/// <summary> /// Overwrite the clockspeed (see Settings.ClockSpeed for details) /// </summary> /// <param name="clockSpeed"></param> private void WriteClockSpeed(ClockSpeed clockSpeed) { byte speed; short invertedModifier; switch (clockSpeed) { default: case ClockSpeed.Default: speed = 3; invertedModifier = -2; break; case ClockSpeed.VerySlow: speed = 1; invertedModifier = 0; break; case ClockSpeed.Slow: speed = 2; invertedModifier = -1; break; case ClockSpeed.Fast: speed = 6; invertedModifier = -4; break; case ClockSpeed.VeryFast: speed = 9; invertedModifier = -6; break; case ClockSpeed.SuperFast: speed = 18; invertedModifier = -12; break; } ResourceUtils.ApplyHack(Values.ModsDirectory + "fix-clock-speed"); var codeFileAddress = 0xB3C000; var hackAddressOffset = 0x8A674; var modificationOffset = 0x1B; ReadWriteUtils.WriteToROM(codeFileAddress + hackAddressOffset + modificationOffset, speed); var invertedModifierOffsets = new List <int> { 0xB1B8E, 0x7405E }; foreach (var offset in invertedModifierOffsets) { ReadWriteUtils.WriteToROM(codeFileAddress + offset, (ushort)invertedModifier); } }
private void WriteMuteMusic() { if (_settings.NoBGM) { var codeFileAddress = 0xB3C000; var offset = 0x102350; // address for branch when scene music is loaded ReadWriteUtils.WriteToROM(codeFileAddress + offset, 0x1000); // change to always branch (do not load) } }
/// <summary> /// Patch existing <see cref="MMFile"/> files. /// </summary> public void WriteToROM(Symbols symbols) { foreach (var data in _data) { if (TABLE_END <= data.Address && data.Address < symbols.PayloadStart) { ReadWriteUtils.WriteToROM((int)data.Address, data.Data); } } }
/// <summary> /// Write a <see cref="DPadConfig"/> to the ROM. /// </summary> /// <remarks>Assumes <see cref="Patcher"/> file has been inserted.</remarks> /// <param name="config">D-Pad config</param> public void WriteDPadConfig(DPadConfig config) { // Write DPad config bytes. var addr = this["DPAD_CONFIG"]; ReadWriteUtils.WriteToROM((int)addr, config.Pad.Bytes); // Write DPad state WriteDPadState(config.State); }
/// <summary> /// Write a <see cref="DPadConfig"/> to the ROM. /// </summary> /// <remarks>Assumes <see cref="Patcher"/> file has been inserted.</remarks> /// <param name="config">D-Pad config</param> void WriteDPadConfigLegacy(DPadConfig config) { // Write DPad config bytes. var addr = this["DPAD_CONFIG"]; ReadWriteUtils.WriteToROM((int)addr, config.Pad.Bytes); // Write DPad state byte. addr = this["DPAD_STATE"]; ReadWriteUtils.WriteToROM((int)addr, (byte)config.State); }
private void WriteFreeItems(params Item[] items) { Dictionary <int, byte> startingItems = new Dictionary <int, byte>(); PutOrCombine(startingItems, 0xC5CE72, 0x10); // add Song of Time var itemList = items.ToList(); if (_settings.CustomStartingItemList != null) { itemList.AddRange(_settings.CustomStartingItemList); } itemList.Add(Item.StartingHeartContainer1); while (itemList.Count(item => item.Name() == "Piece of Heart") >= 4) { itemList.Add(Item.StartingHeartContainer1); for (var i = 0; i < 4; i++) { var heartPiece = itemList.First(item => item.Name() == "Piece of Heart"); itemList.Remove(heartPiece); } } itemList = itemList .GroupBy(item => ItemUtils.ForbiddenStartTogether.FirstOrDefault(fst => fst.Contains(item))) .SelectMany(g => g.Key == null ? g.ToList() : g.OrderByDescending(item => g.Key.IndexOf(item)).Take(1)) .ToList(); foreach (var item in itemList) { var startingItemValues = item.GetAttributes <StartingItemAttribute>(); if (!startingItemValues.Any() && !_settings.NoStartingItems) { throw new Exception($@"Invalid starting item ""{item}"""); } foreach (var startingItem in startingItemValues) { PutOrCombine(startingItems, startingItem.Address, startingItem.Value, startingItem.IsAdditional); } } foreach (var kvp in startingItems) { ReadWriteUtils.WriteToROM(kvp.Key, kvp.Value); } if (itemList.Count(item => item.Name() == "Heart Container") == 1) { ReadWriteUtils.WriteToROM(0x00B97E8F, 0x0C); // reduce low health beep threshold } }
private void WriteFreeItem(int Item) { ReadWriteUtils.WriteToROM(Items.ITEM_ADDRS[Item], Items.ITEM_VALUES[Item]); switch (Item) { case Items.ItemBow: ReadWriteUtils.WriteToROM(0xC5CE6F, (byte)0x01); break; case Items.ItemBombBag: ReadWriteUtils.WriteToROM(0xC5CE6F, (byte)0x08); break; case Items.UpgradeRazorSword: //sword upgrade ReadWriteUtils.WriteToROM(0xC5CE00, (byte)0x4E); break; case Items.UpgradeGildedSword: ReadWriteUtils.WriteToROM(0xC5CE00, (byte)0x4F); break; case Items.UpgradeBigQuiver: //quiver upgrade ReadWriteUtils.WriteToROM(0xC5CE6F, (byte)0x02); break; case Items.UpgradeBiggestQuiver: ReadWriteUtils.WriteToROM(0xC5CE6F, (byte)0x03); break; case Items.UpgradeBigBombBag: //bomb bag upgrade ReadWriteUtils.WriteToROM(0xC5CE6F, (byte)0x10); break; case Items.UpgradeBiggestBombBag: ReadWriteUtils.WriteToROM(0xC5CE6F, (byte)0x18); break; default: break; } }
private void WriteFreeItems(params Item[] items) { Dictionary <int, byte> startingItems = new Dictionary <int, byte>(); PutOrCombine(startingItems, 0xC5CE72, 0x10); // add Song of Time // can't start with more than 15 hearts with this method. heart container value is two bytes PutOrCombine(startingItems, 0xC5CDE9, 0x10, true); // add Heart Container PutOrCombine(startingItems, 0xC5CDEB, 0x10, true); // add current health PutOrCombine(startingItems, 0xC40E1B, 0x10, true); // add respawn health var itemList = items.ToList(); while (itemList.Count(item => item.Name() == "Piece of Heart") >= 4) { itemList.Add(Item.StartingHeartContainer1); for (var i = 0; i < 4; i++) { var heartPiece = itemList.First(item => item.Name() == "Piece of Heart"); itemList.Remove(heartPiece); } } foreach (var item in itemList) { var startingItemValues = item.GetAttributes <StartingItemAttribute>(); if (!startingItemValues.Any() && !_settings.NoStartingItems) { throw new Exception($@"Invalid starting item ""{item}"""); } foreach (var startingItem in startingItemValues) { PutOrCombine(startingItems, startingItem.Address, startingItem.Value, startingItem.IsAdditional); } } foreach (var kvp in startingItems) { ReadWriteUtils.WriteToROM(kvp.Key, kvp.Value); } }
private void WriteBlastMaskCooldown() { ushort value; switch (_settings.BlastMaskCooldown) { default: case BlastMaskCooldown.Default: value = 0x136; // 310 frames break; case BlastMaskCooldown.Instant: value = 0x1; // 1 frame break; case BlastMaskCooldown.VeryShort: value = 0x20; // 32 frames break; case BlastMaskCooldown.Short: value = 0x80; // 128 frames break; case BlastMaskCooldown.Long: value = 0x200; // 512 frames break; case BlastMaskCooldown.VeryLong: value = 0x400; // 1024 frames break; } var codeFileAddress = 0x00CA7F00; var offset = 0x002766; ReadWriteUtils.WriteToROM(codeFileAddress + offset, value); }
private void WriteFreeItems(params int[] itemIds) { Dictionary <int, byte> startingItems = new Dictionary <int, byte>(); if (!itemIds.Contains(Items.UpgradeRazorSword) && !itemIds.Contains(Items.UpgradeGildedSword)) { PutOrCombine(startingItems, 0xC5CE21, 0x01); // add Kokiri Sword } if (!itemIds.Contains(Items.UpgradeMirrorShield)) { PutOrCombine(startingItems, 0xC5CE21, 0x10); // add Hero's Shield } PutOrCombine(startingItems, 0xC5CE72, 0x10); // add Song of Time foreach (var id in itemIds) { var itemAddress = Items.ITEM_ADDRS[id]; var itemValue = Items.ITEM_VALUES[id]; PutOrCombine(startingItems, itemAddress, itemValue, ItemUtils.IsHeartPiece(id)); switch (id) { case Items.ItemBow: PutOrCombine(startingItems, 0xC5CE6F, 0x01); break; case Items.ItemBombBag: PutOrCombine(startingItems, 0xC5CE6F, 0x08); break; case Items.UpgradeRazorSword: //sword upgrade startingItems[0xC5CE00] = 0x4E; break; case Items.UpgradeGildedSword: startingItems[0xC5CE00] = 0x4F; break; case Items.UpgradeBigQuiver: //quiver upgrade PutOrCombine(startingItems, 0xC5CE6F, 0x02); break; case Items.UpgradeBiggestQuiver: PutOrCombine(startingItems, 0xC5CE6F, 0x03); break; case Items.UpgradeBigBombBag: //bomb bag upgrade PutOrCombine(startingItems, 0xC5CE6F, 0x10); break; case Items.UpgradeBiggestBombBag: PutOrCombine(startingItems, 0xC5CE6F, 0x18); break; default: break; } } foreach (var kvp in startingItems) { ReadWriteUtils.WriteToROM(kvp.Key, kvp.Value); } }
/// <summary> /// Write <see cref="MimicItemTable"/> table to ROM. /// </summary> /// <param name="table">Table</param> public void WriteMimicItemTable(MimicItemTable table) { var addr = this["ITEM_OVERRIDE_ENTRIES"]; ReadWriteUtils.WriteToROM((int)addr, table.Build()); }