/// <summary> /// Perform the randomization based on the seed and user-provided settings, and then /// generate the new ROM. /// </summary> public static String RandomizerCreate(String in_SeedString) { // Initialize the seed if (null == in_SeedString) { RandomMM2.mSeed = SeedFactory.Create(GeneratorType.MT19937); } else { RandomMM2.mSeed = SeedFactory.Create(GeneratorType.MT19937, in_SeedString); } //Random = new Random(RandomMM2.mSeed); //RNGCosmetic = new Random(RandomMM2.mSeed); // 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(Settings.IsFlashingDisabled); // 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); } // Create randomization patch Patch = new Patch(); // In tournament mode, offset the seed by 1 call, making seeds mode-dependent if (Settings.IsSpoilerFree) { RandomMM2.mSeed.Next(); } // Conduct randomization of Gameplay Modules foreach (IRandomizer randomizer in Randomizers) { randomizer.Randomize(Patch, RandomMM2.mSeed); Debug.WriteLine(randomizer); } // Conduct randomization of Cosmetic Modules foreach (IRandomizer cosmetic in CosmeticRandomizers) { cosmetic.Randomize(Patch, RandomMM2.mSeed); 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); } if (Settings.IsFlashingDisabled) { MiscHacks.DisableScreenFlashing(Patch, Settings); } MiscHacks.SetHitPointChargingSpeed(Patch, Settings.HitPointChargingSpeed); MiscHacks.SetWeaponEnergyChargingSpeed(Patch, Settings.WeaponEnergyChargingSpeed); MiscHacks.SetEnergyTankChargingSpeed(Patch, Settings.EnergyTankChargingSpeed); MiscHacks.SetRobotMasterEnergyChargingSpeed(Patch, Settings.RobotMasterEnergyChargingSpeed); MiscHacks.SetCastleBossEnergyChargingSpeed(Patch, Settings.CastleBossEnergyChargingSpeed); MiscHacks.DrawTitleScreenChanges(Patch, RandomMM2.mSeed.Identifier, Settings); MiscHacks.SetWily5NoMusicChange(Patch); MiscHacks.NerfDamageValues(Patch); MiscHacks.SetETankKeep(Patch); MiscHacks.PreventETankUseAtFullLife(Patch); MiscHacks.SetFastBossDefeatTeleport(Patch); if (Settings.ReduceUnderwaterLag) { MiscHacks.ReduceUnderwaterLag(Patch); } if (Settings.DisableDelayScrolling) { MiscHacks.DisableDelayScroll(Patch); } // Create file name based on seed and game region String newFileName = $"MM2-RNG-{RandomMM2.mSeed.Identifier} ({RandomMM2.mSeed.SeedString}).nes"; //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); }
/// <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) { // 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.IsTournamentMode) { 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); } if (Settings.IsEnemiesRandom) { MiscHacks.FixM445PaletteGlitch(Patch); } // Apply final optional gameplay modifications if (Settings.FastText) { MiscHacks.SetFastText(Patch); } if (Settings.BurstChaserMode) { MiscHacks.SetBurstChaser(Patch); } MiscHacks.DrawTitleScreenChanges(Patch, Seed, Settings.IsTournamentMode); MiscHacks.SetWily5NoMusicChange(Patch); MiscHacks.FixDamageValues(Patch); MiscHacks.SetETankKeep(Patch); MiscHacks.SkipItemGetPages(Patch); MiscHacks.PreventETankUseAtFullLife(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 var assembly = Assembly.GetExecutingAssembly(); 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, and stage changes) Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_musicpatch); Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_prepatch); // 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); } }
/// <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) { randomStages = new RStages(); randomWeaponGet = new RWeaponGet(); randomWeaponBehavior = new RWeaponBehavior(); randomWeaknesses = new RWeaknesses(true); randomBossAI = new RBossAI(); randomItemGet = new RItemGet(); randomTeleporters = new RTeleporters(); randomEnemies = new REnemies(); randomEnemyWeakness = new REnemyWeaknesses(); randomBossInBossRoom = new RBossRoom(); randomTilemap = new RTilemap(); randomColors = new RColors(); randomMusic = new RMusic(); rWeaponNames = new RText(); Randomizers = new List<IRandomizer>(); // Add randomizers according to each flag 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); } if (Settings.IsColorsRandom) { Randomizers.Add(randomColors); } if (Settings.IsBGMRandom) { Randomizers.Add(randomMusic); } if (Settings.IsWeaponNamesRandom) { Randomizers.Add(rWeaponNames); } // Instantiate RNG object r based on RandomMM2.Seed InitializeSeed(); // Create randomization patch Patch = new Patch(); foreach (IRandomizer randomizer in Randomizers) { randomizer.Randomize(Patch, Random); Debug.WriteLine(randomizer); } // Create patch with additional modifications if (Settings.FastText) { MiscHacks.SetFastText(Patch, Settings.IsJapanese); } if (Settings.BurstChaserMode) { MiscHacks.SetBurstChaser(Patch, Settings.IsJapanese); } if (Settings.Is8StagesRandom || Settings.IsWeaponsRandom) { MiscHacks.FixPortraits(Patch, Settings.Is8StagesRandom, randomStages, Settings.IsWeaponsRandom, randomWeaponGet); } if (Settings.IsEnemiesRandom) { MiscHacks.FixM445PaletteGlitch(Patch); } if (!Settings.IsJapanese) { MiscHacks.DrawTitleScreenChanges(Patch, Seed); } MiscHacks.SetWily5NoMusicChange(Patch, Settings.IsJapanese); MiscHacks.FixDamageValues(Patch); MiscHacks.SetETankKeep(Patch); MiscHacks.SkipItemGetPages(Patch); // Create file name based on seed and game region string newfilename = (Settings.IsJapanese) ? "RM2" : "MM2"; string seedAlpha = SeedConvert.ConvertBase10To26(Seed); newfilename = $"{newfilename}-RNG-{seedAlpha}.nes"; var assembly = Assembly.GetExecutingAssembly(); if (fromClientApp) { //File.Copy(Settings.SourcePath, TempFileName, true); using (Stream stream = assembly.GetManifestResourceStream("MM2Randomizer.Resources.MM2.nes")) { using (Stream output = File.OpenWrite(TempFileName)) { stream.CopyTo(output); } } // Apply pre-patch changes via IPS patch (manual title screen, stage select, and stage changes) Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_musicpatch); Patch.ApplyIPSPatch(TempFileName, Properties.Resources.mm2rng_prepatch); // 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; 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 = assembly.GetManifestResourceStream("MM2Randomizer.Resources.MM2.nes")) { 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; } }