/// <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);
            }
        }