/// <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);
        }
Example #2
0
        /// <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);
            }
        }
Example #3
0
        /// <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;
            }
        }