/// <summary>
        /// The scripting randomization will be complete at this stage, so access to which levels
        /// are available, which are unarmed, ammoless etc is accurate at this point. The list of
        /// levels is always in the original sequence when accessed here, but can be sorted by level
        /// sequence if it's preferred to add an additional randomization factor. The save monitor
        /// is used to report progress and checks should be performed regularly on IsCancelled.
        /// </summary>
        protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMonitor monitor)
        {
            List <TR23ScriptedLevel> levels = new List <TR23ScriptedLevel>
                                              (
                scriptEditor.ScriptedLevels.Cast <TR23ScriptedLevel>().ToList()
                                              );

            // Optionally sort based on randomized sequencing. Perhaps this should be an option for users?

            /*levels.Sort(delegate (TR23ScriptedLevel lvl1, TR23ScriptedLevel lvl2)
             * {
             *  return lvl1.Sequence.CompareTo(lvl2.Sequence);
             * });*/

            string wipDirectory = _io.WIPOutputDirectory.FullName;

            if (!monitor.IsCancelled && RandomizeSecrets)
            {
                monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing secrets");
                new SecretReplacer
                {
                    AllowHard           = HardSecrets,
                    Levels              = levels,
                    BasePath            = wipDirectory,
                    SaveMonitor         = monitor,
                    IsDevelopmentModeOn = DevelopmentMode
                }.Randomize(SecretSeed);
            }

            if (!monitor.IsCancelled && RandomizeItems)
            {
                monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing items");
                new ItemRandomizer
                {
                    Levels              = levels,
                    BasePath            = wipDirectory,
                    SaveMonitor         = monitor,
                    IncludeKeyItems     = IncludeKeyItems,
                    IsDevelopmentModeOn = DevelopmentMode
                }.Randomize(ItemSeed);
            }

            if (!monitor.IsCancelled && RandomizeEnemies)
            {
                monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing enemies");
                new EnemyRandomizer
                {
                    Levels      = levels,
                    BasePath    = wipDirectory,
                    SaveMonitor = monitor
                }.Randomize(EnemySeed);
            }

            if (!monitor.IsCancelled && RandomizeTextures)
            {
                monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing textures");
                new TextureRandomizer
                {
                    Levels      = levels,
                    BasePath    = wipDirectory,
                    SaveMonitor = monitor
                }.Randomize(TextureSeed);
            }
        }
Beispiel #2
0
        /// <summary>
        /// The scripting randomization will be complete at this stage, so access to which levels
        /// are available, which are unarmed, ammoless etc is accurate at this point. The list of
        /// levels is always in the original sequence when accessed here, but can be sorted by level
        /// sequence if it's preferred to add an additional randomization factor. The save monitor
        /// is used to report progress and checks should be performed regularly on IsCancelled.
        /// </summary>
        protected override void SaveImpl(AbstractTRScriptEditor scriptEditor, TRSaveMonitor monitor)
        {
            List <TR23ScriptedLevel> levels = new List <TR23ScriptedLevel>
                                              (
                scriptEditor.EnabledScriptedLevels.Cast <TR23ScriptedLevel>().ToList()
                                              );

            if (scriptEditor.GymAvailable)
            {
                levels.Add(scriptEditor.AssaultLevel as TR23ScriptedLevel);
            }

            // Optionally sort based on randomized sequencing. Perhaps this should be an option for users?

            /*levels.Sort(delegate (TR23ScriptedLevel lvl1, TR23ScriptedLevel lvl2)
             * {
             *  return lvl1.Sequence.CompareTo(lvl2.Sequence);
             * });*/

            string wipDirectory = _io.WIPOutputDirectory.FullName;

            // Texture monitoring is needed between enemy and texture randomization
            // to track where imported enemies are placed.
            using (TexturePositionMonitorBroker textureMonitor = new TexturePositionMonitorBroker())
            {
                if (!monitor.IsCancelled && RandomizeSecrets)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing secrets");
                    new SecretReplacer
                    {
                        AllowHard           = HardSecrets,
                        AllowGlitched       = GlitchedSecrets,
                        Levels              = levels,
                        BasePath            = wipDirectory,
                        SaveMonitor         = monitor,
                        IsDevelopmentModeOn = DevelopmentMode
                    }.Randomize(SecretSeed);
                }

                if (!monitor.IsCancelled && RandomizeAudio)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing audio tracks");
                    new AudioRandomizer
                    {
                        ScriptEditor        = scriptEditor as TR23ScriptEditor,
                        Levels              = levels,
                        BasePath            = wipDirectory,
                        SaveMonitor         = monitor,
                        ChangeTriggerTracks = ChangeTriggerTracks
                    }.Randomize(AudioSeed);
                }

                if (!monitor.IsCancelled && DeduplicateTextures)
                {
                    // This is needed to make as much space as possible available for cross-level enemies.
                    // We do this if we are implementing cross-level enemies OR if randomizing textures,
                    // as the texture mapping is optimised for levels that have been deduplicated.
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Deduplicating textures");
                    new TextureDeduplicator
                    {
                        Levels      = levels,
                        BasePath    = wipDirectory,
                        SaveMonitor = monitor
                    }.Deduplicate();
                }

                if (!monitor.IsCancelled && RandomizeNightMode)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing night mode");
                    new NightModeRandomizer
                    {
                        Levels      = levels,
                        BasePath    = wipDirectory,
                        SaveMonitor = monitor,
                        NumLevels   = NightModeCount
                    }.Randomize(NightModeSeed);
                }

                ItemRandomizer itemRandomizer = null;
                if (!monitor.IsCancelled && RandomizeItems)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, string.Format("Randomizing standard{0} items", IncludeKeyItems ? " and key" : string.Empty));
                    (itemRandomizer = new ItemRandomizer
                    {
                        Levels = levels,
                        BasePath = wipDirectory,
                        SaveMonitor = monitor,
                        IncludeKeyItems = IncludeKeyItems,
                        PerformEnemyWeighting = RandomizeEnemies && CrossLevelEnemies,
                        TextureMonitor = textureMonitor,
                        IsDevelopmentModeOn = DevelopmentMode
                    }).Randomize(ItemSeed);
                }

                if (!monitor.IsCancelled && RandomizeEnemies)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing enemies");
                    new EnemyRandomizer
                    {
                        Levels             = levels,
                        BasePath           = wipDirectory,
                        SaveMonitor        = monitor,
                        CrossLevelEnemies  = CrossLevelEnemies,
                        ProtectMonks       = ProtectMonks,
                        DocileBirdMonsters = DocileBirdMonsters,
                        TextureMonitor     = textureMonitor
                    }.Randomize(EnemySeed);
                }

                // Randomize ammo/weapon in unarmed levels post enemy randomization
                if (!monitor.IsCancelled && RandomizeItems)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing unarmed level items");
                    itemRandomizer.RandomizeAmmo();
                }

                if (!monitor.IsCancelled && RandomizeStartPosition)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing start positions");
                    new StartPositionRandomizer
                    {
                        Levels          = levels,
                        BasePath        = wipDirectory,
                        SaveMonitor     = monitor,
                        RotateOnly      = RotateStartPositionOnly,
                        DevelopmentMode = DevelopmentMode
                    }.Randomize(StartPositionSeed);
                }

                if (!monitor.IsCancelled && RandomizeOutfits)
                {
                    monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing outfits");
                    new OutfitRandomizer
                    {
                        Levels          = levels,
                        BasePath        = wipDirectory,
                        SaveMonitor     = monitor,
                        PersistOutfits  = PersistOutfits,
                        RandomlyCutHair = RandomlyCutHair,
                        TextureMonitor  = textureMonitor
                    }.Randomize(OutfitSeed);
                }

                if (!monitor.IsCancelled)
                {
                    if (RandomizeTextures)
                    {
                        monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing textures");
                        new TextureRandomizer
                        {
                            Levels              = levels,
                            BasePath            = wipDirectory,
                            SaveMonitor         = monitor,
                            PersistVariants     = PersistTextureVariants,
                            RetainKeySprites    = RetainKeySpriteTextures,
                            RetainSecretSprites = RetainSecretSpriteTextures,
                            NightModeOnly       = !RandomizeTextures,
                            TextureMonitor      = textureMonitor
                        }.Randomize(TextureSeed);
                    }
                    else if (RandomizeNightMode)
                    {
                        monitor.FireSaveStateBeginning(TRSaveCategory.Custom, "Randomizing night mode textures");
                        new TextureRandomizer
                        {
                            Levels         = levels,
                            BasePath       = wipDirectory,
                            SaveMonitor    = monitor,
                            NightModeOnly  = true,
                            TextureMonitor = textureMonitor
                        }.Randomize(NightModeSeed);
                    }
                }
            }
        }