/// <summary> /// Perform the randomization based on the seed and user-provided settings, and then /// generate the new ROM. /// </summary> public static string RandomizerCreate(bool fromClientApp, int seed) { Seed = seed; // List of randomizer modules to use; will add modules based on checkbox states Randomizers = new List <IRandomizer>(); CosmeticRandomizers = new List <IRandomizer>(); ///========================== /// "CORE" MODULES ///========================== // NOTE: Just in case, link RStages, RWeaponGet, and RTeleporter into one "Core Randomizer" module // Their interdependencies are too risky to separate as options, and likely nobody will want to customize this part anyways. // Random portrait locations on stage select randomStages = new RStages(); // Random weapon awarded from each stage // WARNING: May be dependent on RTeleporters, verify? // WARNING: May be dependent on RStages randomWeaponGet = new RWeaponGet(); // Random teleporter destinations in Wily 5 randomTeleporters = new RTeleporters(); ///========================== /// "GAMEPLAY SEED" MODULES ///========================== // Caution: RWeaknesses depends on this randomWeaponBehavior = new RWeaponBehavior(); // Depends on RWeaponBehavior (ammo), can use default values randomWeaknesses = new RWeaknesses(); // Caution: RText depends on this, but default values will be used if not enabled. randomBossInBossRoom = new RBossRoom(); // Independent randomBossAI = new RBossAI(); // Independent randomItemGet = new RItemGet(); // Independent randomEnemies = new REnemies(); // Independent randomEnemyWeakness = new REnemyWeaknesses(); // Independent randomTilemap = new RTilemap(); ///========================== /// "COSMETIC SEED" MODULES ///========================== // Caution: Depends on RBossRoom, but can use default values if its not enabled. rWeaponNames = new RText(); // Independent randomColors = new RColors(); // Independent randomMusic = new RMusic(); // Add randomizers according to each flag ///========================== /// "GAMEPLAY SEED" MODULES ///========================== if (Settings.Is8StagesRandom) { Randomizers.Add(randomStages); } if (Settings.IsWeaponsRandom) { Randomizers.Add(randomWeaponGet); } if (Settings.IsWeaponBehaviorRandom) { Randomizers.Add(randomWeaponBehavior); } if (Settings.IsWeaknessRandom) { Randomizers.Add(randomWeaknesses); } if (Settings.IsBossAIRandom) { Randomizers.Add(randomBossAI); } if (Settings.IsItemsRandom) { Randomizers.Add(randomItemGet); } if (Settings.IsTeleportersRandom) { Randomizers.Add(randomTeleporters); } if (Settings.IsEnemiesRandom) { Randomizers.Add(randomEnemies); } if (Settings.IsEnemyWeaknessRandom) { Randomizers.Add(randomEnemyWeakness); } if (Settings.IsBossInBossRoomRandom) { Randomizers.Add(randomBossInBossRoom); } if (Settings.IsTilemapChangesEnabled) { Randomizers.Add(randomTilemap); } ///========================== /// "COSMETIC SEED" MODULES ///========================== if (Settings.IsColorsRandom) { CosmeticRandomizers.Add(randomColors); } if (Settings.IsBGMRandom) { CosmeticRandomizers.Add(randomMusic); } if (Settings.IsWeaponNamesRandom) { CosmeticRandomizers.Add(rWeaponNames); } // Instantiate RNG object r based on RandomMM2.Seed InitializeSeed(); // Create randomization patch Patch = new Patch(); // In tournament mode, offset the seed by 1 call, making seeds mode-dependent if (Settings.IsSpoilerFree) { Random.Next(); RNGCosmetic.Next(); } // Conduct randomization of Gameplay Modules foreach (IRandomizer randomizer in Randomizers) { randomizer.Randomize(Patch, Random); Debug.WriteLine(randomizer); } // Conduct randomization of Cosmetic Modules foreach (IRandomizer cosmetic in CosmeticRandomizers) { cosmetic.Randomize(Patch, RNGCosmetic); Debug.WriteLine(cosmetic); } // Apply additional required incidental modifications if (Settings.Is8StagesRandom || Settings.IsWeaponsRandom) { MiscHacks.FixPortraits(Patch, Settings.Is8StagesRandom, randomStages, Settings.IsWeaponsRandom, randomWeaponGet); MiscHacks.FixWeaponLetters(Patch, randomWeaponGet, randomStages, rWeaponNames); } if (Settings.IsEnemiesRandom) { MiscHacks.FixM445PaletteGlitch(Patch); } // Apply final optional gameplay modifications if (Settings.FastText) { MiscHacks.SetFastWeaponGetText(Patch); MiscHacks.SetFastReadyText(Patch); MiscHacks.SetFastWilyMap(Patch); MiscHacks.SkipItemGetPages(Patch); } if (Settings.BurstChaserMode) { MiscHacks.SetBurstChaser(Patch); } MiscHacks.DrawTitleScreenChanges(Patch, Seed, Settings); MiscHacks.SetWily5NoMusicChange(Patch); MiscHacks.NerfDamageValues(Patch); MiscHacks.SetETankKeep(Patch); MiscHacks.PreventETankUseAtFullLife(Patch); MiscHacks.SetFastBossDefeatTeleport(Patch); // Create file name based on seed and game region string seedAlpha = SeedConvert.ConvertBase10To26(Seed); string newfilename = $"MM2-RNG-{seedAlpha}.nes"; // Apply patch and deliver the ROM; different routine for client vs. web app if (fromClientApp) { //File.Copy(Settings.SourcePath, TempFileName, true); //using (Stream stream = assembly.GetManifestResourceStream("MM2Randomizer.Resources.MM2.nes")) // Load user provided ROM using (Stream stream = new FileStream(Settings.SourcePath, FileMode.Open, FileAccess.Read)) { using (Stream output = File.OpenWrite(TempFileName)) { stream.CopyTo(output); } } // Apply pre-patch changes via IPS patch (manual title screen, stage select, stage changes, player sprite) Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_musicpatch); Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_prepatch); MiscHacks.SetNewMegaManSprite(Patch, TempFileName, Settings.SelectedPlayer); // Apply patch with randomized content Patch.ApplyRandoPatch(TempFileName); // If a file of the same seed already exists, delete it if (File.Exists(newfilename)) { File.Delete(newfilename); } // Finish the copy/rename and open Explorer at that location File.Move(TempFileName, newfilename); RecentlyCreatedFileName = newfilename; Settings.HashValidationMessage = "Successfully copied and patched! File: " + newfilename; return(newfilename); } else { //File.Copy(Settings.SourcePath, TempFileName, true); string serverDir = $@"C:\mm2rng\{seedAlpha}"; Directory.CreateDirectory(serverDir); string serverPathTemp = Path.Combine(serverDir, TempFileName); string serverPathNew = Path.Combine(serverDir, newfilename); using (Stream stream = new FileStream("MM2.nes", FileMode.Open)) { using (Stream output = File.OpenWrite(serverPathTemp)) { stream.CopyTo(output); } } // Apply pre-patch changes via IPS patch (manual title screen, stage select, and stage changes) Patch.ApplyIPSPatch(serverPathTemp, Properties.Resources.mm2rng_musicpatch); Patch.ApplyIPSPatch(serverPathTemp, Properties.Resources.mm2rng_prepatch); // Apply patch with randomized content Patch.ApplyRandoPatch(serverPathTemp); // If a file of the same seed already exists, delete it if (File.Exists(serverPathNew)) { File.Delete(serverPathNew); } // Finish the copy/rename and open Explorer at that location File.Move(serverPathTemp, serverPathNew); RecentlyCreatedFileName = serverPathNew; return(serverPathNew); } }