public void FinalizeSettings(CosmeticSettings settings) { if (settings.Music == Models.Music.Random) { SequenceMaskFileIndex = RomUtils.AppendFile(new byte[0x80 * SEQUENCE_DATA_SIZE]); } else { SequenceMaskFileIndex = null; } }
private void WriteStartupStrings() { if (_settings.LogicMode == LogicMode.Vanilla) { //ResourceUtils.ApplyHack(ModsDir + "postman-testing"); return; } Version v = Assembly.GetExecutingAssembly().GetName().Version; RomUtils.SetStrings(Values.ModsDirectory + "logo-text", $"v{v}", _settings.ToString()); }
/// <summary> /// Load <see cref="Symbols"/> from a special <see cref="MMFile"/> already in the ROM. /// </summary> /// <returns>Symbols</returns> public static Symbols FromROM() { int index = RomUtils.AddrToFile((int)MMFILE_START); // Might be unable to find MMFile with Symbols data for older patch files if (index < 0) { return(null); } var file = RomData.MMFileList[index]; return(Symbols.FromMMFile(file)); }
public void InitializeTable() { Dictionary <ushort, MessageEntry> messageTable = new Dictionary <ushort, MessageEntry>(); int fileIndex = RomUtils.GetFileIndexForWriting(MESSAGE_TABLE_ADDRESS); MMFile file = RomData.MMFileList[fileIndex]; int code_baseAddr = MESSAGE_TABLE_ADDRESS - file.Addr; var code_data = file.Data; fileIndex = RomUtils.GetFileIndexForWriting(MESSAGE_DATA_ADDRESS); file = RomData.MMFileList[fileIndex]; var message_data = file.Data; while (true) { ushort textId = ReadWriteUtils.Arr_ReadU16(code_data, code_baseAddr); if (textId >= 0xFFFF) { break; } int address = ReadWriteUtils.Arr_ReadS32(code_data, code_baseAddr + 4) & 0xFFFFFF; byte[] header = new byte[11]; Array.Copy(message_data, address, header, 0, 11); int cur = address + 11 - 1; string message = ""; do { cur++; message += (char)message_data[cur]; }while (message_data[cur] != 0xBF); MessageEntry messageEntry = new MessageEntry() { Id = textId, Header = header, Message = message }; messageTable.Add(textId, messageEntry); code_baseAddr += 8; } messages = messageTable; }
public static void WriteEntrances(int[] olde, int[] newe) { int f = RomUtils.GetFileIndexForWriting(0xC5BC64); uint[] data = new uint[newe.Length]; for (int i = 0; i < newe.Length; i++) { data[i] = ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, GetEntranceAddr(newe[i])); } for (int i = 0; i < newe.Length; i++) { ReadWriteUtils.Arr_WriteU32(RomData.MMFileList[f].Data, GetEntranceAddr(olde[i]), data[i]); } }
private static int GetEntranceAddr(int ent) { int offset = ((ent >> 9) * 12) + 0xC5BC64; int f = RomUtils.GetFileIndexForWriting(offset); offset -= RomData.MMFileList[f].Addr; uint p1 = ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, offset); offset = ((ent >> 4) & 0x1F) * 4; p1 = (uint)((p1 & 0xFFFFFF) + 0xA96540 - RomData.MMFileList[f].Addr); p1 = ReadWriteUtils.Arr_ReadU32(RomData.MMFileList[f].Data, (int)(p1 + offset)); p1 = (uint)((p1 & 0xFFFFFF) + 0xA96540 - RomData.MMFileList[f].Addr); offset = (ent & 0xF) << 2; return((int)p1 + offset); }
/// <summary> /// Apply patches. /// </summary> /// <param name="symbols">Symbols</param> /// <param name="options">Options</param> public void Apply(Symbols symbols, AsmOptionsGameplay options) { // Write patch data to existing MMFiles WriteToROM(symbols); // For our custom data, create and insert our own MMFile var file = CreateMMFile(symbols); RomUtils.AppendFile(file); // Encode Symbols into a special MMFile and insert that too var symbolsFile = symbols.CreateMMFile(); RomUtils.AppendFile(symbolsFile); // Write subset of configuration (hardcoded into patch) symbols.ApplyConfiguration(options); }
/// <summary> /// Apply patches. /// </summary> /// <param name="symbols">Symbols</param> /// <param name="options">Options</param> public void Apply(Symbols symbols, PatcherOptions options) { // Write patch data to existing MMFiles WriteToROM(symbols); // For our custom data, create and insert our own MMFile var file = CreateMMFile(symbols); RomUtils.AppendFile(file); // Encode Symbols into a special MMFile and insert that too var symbolsFile = symbols.CreateMMFile(); RomUtils.AppendFile(symbolsFile); // Write our D-Pad config symbols.WriteDPadConfig(options.DPadConfig); }
public static void DisableCombatMusicOnEnemy(GameObjects.Actor actor) { int actorInitVarRomAddr = actor.GetAttribute<ActorInitVarOffsetAttribute>().Offset; /// each enemy actor has actor init variables, /// if they have combat music is determined if a flag is set in the seventh byte /// disabling combat music means disabling this bit for most enemies int actorFileID = (int)actor; RomUtils.CheckCompressed(actorFileID); int actorFlagLocation = (actorInitVarRomAddr + 7);// - RomData.MMFileList[ActorFID].Addr; // file offset byte flagByte = RomData.MMFileList[actorFileID].Data[actorFlagLocation]; RomData.MMFileList[actorFileID].Data[actorFlagLocation] = (byte)(flagByte & 0xFB); if (actor == GameObjects.Actor.DekuBabaWithered) // special case: when they regrow music returns { // when they finish regrowing their combat music bit is reset, we need to no-op this to stop it // [ori t3,t1,0x0005] which is [35 2B 00 05] becomes [35 2B 00 01] as the 4 bit is combat music, 1 is R-targetable RomData.MMFileList[actorFileID].Data[0x12BF] = 0x01; } }
private void WriteShopObjects() { RomUtils.CheckCompressed(1325); // trading post var data = RomData.MMFileList[1325].Data.ToList(); data.RemoveRange(0x15C, 4); // reduce end padding from actors list data.InsertRange(0x62, new byte[] { 0x00, 0xC1, 0x00, 0xAF }); // add extra objects data[0x29] += 2; // increase object count by 2 data[0x37] += 4; // add 4 to actor list address RomData.MMFileList[1325].Data = data.ToArray(); RomUtils.CheckCompressed(1503); // bomb shop RomData.MMFileList[1503].Data[0x53] = 0x98; // add extra objects RomData.MMFileList[1503].Data[0x29] += 1; // increase object count by 1 RomUtils.CheckCompressed(1142); // witch shop data = RomData.MMFileList[1142].Data.ToList(); data.RemoveRange(0x78, 4); // reduce end padding from actors list data.InsertRange(0x48, new byte[] { 0x00, 0xC1, 0x00, 0xC1 }); // add extra objects data[0x29] += 2; // increase object count by 2 data[0x37] += 4; // add 4 to actor list address RomData.MMFileList[1142].Data = data.ToArray(); }
/// <summary> /// Try to perform randomization and make rom /// </summary> private void TryRandomize(BackgroundWorker worker, DoWorkEventArgs e) { if (!_settings.GenerateROM && !_settings.GenerateSpoilerLog && !_settings.GeneratePatch) { MessageBox.Show($"No output selected", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } RandomizedResult randomized; if (string.IsNullOrWhiteSpace(_settings.InputPatchFilename)) { try { randomized = _randomizer.Randomize(worker, e); } catch (InvalidDataException ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } catch (Exception ex) { string nl = Environment.NewLine; MessageBox.Show($"Error randomizing logic: {ex.Message}{nl}{nl}Please try a different seed", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (_settings.GenerateSpoilerLog && _settings.LogicMode != LogicMode.Vanilla) { SpoilerUtils.CreateSpoilerLog(randomized, _settings); } } else { randomized = new RandomizedResult(_settings, null); } if (_settings.GenerateROM || _settings.GeneratePatch) { if (!ValidateInputFile()) { return; } if (!RomUtils.ValidateROM(_settings.InputROMFilename)) { MessageBox.Show("Cannot verify input ROM is Majora's Mask (U).", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } _builder = new Builder(randomized); try { _builder.MakeROM(_settings.InputROMFilename, _settings.OutputROMFilename, worker); } catch (Exception ex) { string nl = Environment.NewLine; MessageBox.Show($"Error building ROM: {ex.Message}{nl}{nl}Please contact the development team and provide them more information", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } _settings.InputPatchFilename = null; MessageBox.Show("Generation complete!", "Success", MessageBoxButtons.OK, MessageBoxIcon.None); }
public void MakeROM(string InFile, string FileName, BackgroundWorker worker) { using (BinaryReader OldROM = new BinaryReader(File.Open(InFile, FileMode.Open, FileAccess.Read))) { RomUtils.ReadFileTable(OldROM); _messageTable.InitializeTable(); } List <MMFile> originalMMFileList = null; if (_settings.GeneratePatch) { originalMMFileList = RomData.MMFileList.Select(file => file.Clone()).ToList(); } if (!string.IsNullOrWhiteSpace(_settings.InputPatchFilename)) { worker.ReportProgress(50, "Applying patch..."); RomUtils.ApplyPatch(_settings.InputPatchFilename); } else { // todo music randomizer doesn't work if this is called after WriteItems(); because the reloc-audio hack is hardcoded worker.ReportProgress(50, "Writing audio..."); WriteAudioSeq(); worker.ReportProgress(55, "Writing player model..."); WritePlayerModel(); if (_settings.LogicMode != LogicMode.Vanilla) { worker.ReportProgress(60, "Applying hacks..."); ResourceUtils.ApplyHack(Values.ModsDirectory + "title-screen"); ResourceUtils.ApplyHack(Values.ModsDirectory + "misc-changes"); ResourceUtils.ApplyHack(Values.ModsDirectory + "cm-cs"); ResourceUtils.ApplyHack(Values.ModsDirectory + "fix-song-of-healing"); WriteFileSelect(); } ResourceUtils.ApplyHack(Values.ModsDirectory + "init-file"); ResourceUtils.ApplyHack(Values.ModsDirectory + "fierce-deity-anywhere"); worker.ReportProgress(61, "Writing quick text..."); WriteQuickText(); worker.ReportProgress(62, "Writing cutscenes..."); WriteCutscenes(); worker.ReportProgress(63, "Writing dungeons..."); WriteDungeons(); worker.ReportProgress(64, "Writing gimmicks..."); WriteGimmicks(); worker.ReportProgress(65, "Writing enemies..."); WriteEnemies(); worker.ReportProgress(66, "Writing items..."); WriteItems(); worker.ReportProgress(67, "Writing messages..."); WriteGossipQuotes(); MessageTable.WriteMessageTable(_messageTable); worker.ReportProgress(68, "Writing startup..."); WriteStartupStrings(); if (_settings.GeneratePatch) { worker.ReportProgress(70, "Generating patch..."); RomUtils.CreatePatch(FileName, originalMMFileList); } } worker.ReportProgress(72, "Writing Tatl color..."); WriteTatlColour(); worker.ReportProgress(73, "Writing tunic color..."); WriteTunicColor(); if (_settings.GenerateROM) { worker.ReportProgress(75, "Building ROM..."); byte[] ROM = RomUtils.BuildROM(FileName); if (_settings.OutputVC) { worker.ReportProgress(90, "Building VC..."); VCInjectionUtils.BuildVC(ROM, Values.VCDirectory, Path.ChangeExtension(FileName, "wad")); } } worker.ReportProgress(100, "Done!"); }
public void MakeROM(string InFile, string FileName, BackgroundWorker worker) { using (BinaryReader OldROM = new BinaryReader(File.Open(InFile, FileMode.Open, FileAccess.Read))) { RomUtils.ReadFileTable(OldROM); _messageTable.InitializeTable(); } var originalMMFileList = RomData.MMFileList.Select(file => file.Clone()).ToList(); byte[] hash; if (!string.IsNullOrWhiteSpace(_settings.InputPatchFilename)) { worker.ReportProgress(50, "Applying patch..."); hash = RomUtils.ApplyPatch(_settings.InputPatchFilename); // Apply Asm configuration post-patch WriteAsmConfigPostPatch(); } else { worker.ReportProgress(55, "Writing player model..."); WritePlayerModel(); if (_settings.LogicMode != LogicMode.Vanilla) { worker.ReportProgress(60, "Applying hacks..."); ResourceUtils.ApplyHack(Values.ModsDirectory + "title-screen"); ResourceUtils.ApplyHack(Values.ModsDirectory + "misc-changes"); ResourceUtils.ApplyHack(Values.ModsDirectory + "cm-cs"); ResourceUtils.ApplyHack(Values.ModsDirectory + "fix-song-of-healing"); WriteFileSelect(); } ResourceUtils.ApplyHack(Values.ModsDirectory + "init-file"); ResourceUtils.ApplyHack(Values.ModsDirectory + "fierce-deity-anywhere"); worker.ReportProgress(61, "Writing quick text..."); WriteQuickText(); worker.ReportProgress(62, "Writing cutscenes..."); WriteCutscenes(); worker.ReportProgress(63, "Writing dungeons..."); WriteDungeons(); worker.ReportProgress(64, "Writing gimmicks..."); WriteGimmicks(); worker.ReportProgress(65, "Writing speedups..."); WriteSpeedUps(); worker.ReportProgress(66, "Writing enemies..."); WriteEnemies(); // if shop should match given items { WriteShopObjects(); } worker.ReportProgress(67, "Writing items..."); WriteItems(); worker.ReportProgress(68, "Writing messages..."); WriteGossipQuotes(); MessageTable.WriteMessageTable(_messageTable, _settings.QuickTextEnabled); worker.ReportProgress(69, "Writing startup..."); WriteStartupStrings(); worker.ReportProgress(70, "Writing ASM patch..."); WriteAsmPatch(); worker.ReportProgress(71, _settings.GeneratePatch ? "Generating patch..." : "Computing hash..."); hash = RomUtils.CreatePatch(_settings.GeneratePatch ? FileName : null, originalMMFileList); } worker.ReportProgress(72, "Writing cosmetics..."); WriteTatlColour(); WriteTunicColor(); worker.ReportProgress(73, "Writing music..."); WriteAudioSeq(new Random(BitConverter.ToInt32(hash, 0))); WriteMuteMusic(); worker.ReportProgress(74, "Writing sound effects..."); WriteSoundEffects(new Random(BitConverter.ToInt32(hash, 0))); if (_settings.GenerateROM) { worker.ReportProgress(75, "Building ROM..."); byte[] ROM = RomUtils.BuildROM(FileName); if (_settings.OutputVC) { worker.ReportProgress(90, "Building VC..."); VCInjectionUtils.BuildVC(ROM, _settings.PatcherOptions, Values.VCDirectory, Path.ChangeExtension(FileName, "wad")); } } worker.ReportProgress(100, "Done!"); }
public static string Process(Configuration configuration, int seed, IProgressReporter progressReporter) { var randomizer = new Randomizer(configuration.GameplaySettings, seed); RandomizedResult randomized = null; if (string.IsNullOrWhiteSpace(configuration.OutputSettings.InputPatchFilename)) { try { randomized = randomizer.Randomize(progressReporter); } catch (RandomizationException ex) { string nl = Environment.NewLine; return($"Error randomizing logic: {ex.Message}{nl}{nl}Please try a different seed"); } catch (Exception ex) { return(ex.Message); } if (configuration.OutputSettings.GenerateSpoilerLog && configuration.GameplaySettings.LogicMode != LogicMode.Vanilla) { SpoilerUtils.CreateSpoilerLog(randomized, configuration.GameplaySettings, configuration.OutputSettings); } } if (configuration.OutputSettings.GenerateROM || configuration.OutputSettings.OutputVC || configuration.OutputSettings.GeneratePatch) { if (!RomUtils.ValidateROM(configuration.OutputSettings.InputROMFilename)) { return("Cannot verify input ROM is Majora's Mask (U)."); } var builder = new Builder(randomized, configuration.CosmeticSettings); try { builder.MakeROM(configuration.OutputSettings, progressReporter); } catch (PatchMagicException) { return($"Error applying patch: Not a valid patch file"); } catch (PatchVersionException ex) { return($"Error applying patch: {ex.Message}"); } catch (Exception ex) { string nl = Environment.NewLine; return($"Error building ROM: {ex.Message}{nl}{nl}Please contact the development team and provide them more information"); } } //settings.InputPatchFilename = null; return(null); //return "Generation complete!"; }
public static string Process(Configuration configuration, int seed, IProgressReporter progressReporter) { var randomizer = new Randomizer(configuration.GameplaySettings, seed); RandomizedResult randomized = null; if (string.IsNullOrWhiteSpace(configuration.OutputSettings.InputPatchFilename)) { try { randomized = randomizer.Randomize(progressReporter); if ((configuration.OutputSettings.GenerateSpoilerLog || configuration.OutputSettings.GenerateHTMLLog) && configuration.GameplaySettings.LogicMode != LogicMode.Vanilla) { SpoilerUtils.CreateSpoilerLog(randomized, configuration.GameplaySettings, configuration.OutputSettings); } } catch (RandomizationException ex) { string nl = Environment.NewLine; return($"Error randomizing logic: {ex.Message}{nl}{nl}Please try a different seed"); } catch (Exception ex) { return(ex.Message); } } if (configuration.OutputSettings.GenerateROM || configuration.OutputSettings.OutputVC || configuration.OutputSettings.GeneratePatch) { if (!RomUtils.ValidateROM(configuration.OutputSettings.InputROMFilename)) { return("Cannot verify input ROM is Majora's Mask (U)."); } if (configuration.OutputSettings.OutputVC && !Directory.Exists(Values.VCDirectory)) { return("Error: vc folder is missing and WiiVC wad creation was selected.\n\n" + "If you did not extract the whole randomizer, you must extract the vc folder. If this is a beta release, copy the vc folder from the main release."); } var builder = new Builder(randomized, configuration.CosmeticSettings); try { builder.MakeROM(configuration.OutputSettings, progressReporter); } catch (ROMOverflowException ex) { return($"Error: {ex.Message}"); } catch (PatchMagicException) { return($"Error applying patch: Not a valid patch file"); } catch (PatchVersionException ex) { return($"Error applying patch: {ex.Message}"); } catch (IOException ex) { return(ex.Message); } catch (Exception ex) { string nl = Environment.NewLine; return($"Error building ROM: {ex.Message}{nl}{nl}Please contact the development team and provide them more information"); } } //settings.InputPatchFilename = null; return(null); //return "Generation complete!"; }