示例#1
0
        public static new void Load()
        {
            orig_Load();

            // assign SIDs and CheckpointData.Area for vanilla maps.
            foreach (AreaData area in Areas)
            {
                area.SetSID("Celeste/" + area.Mode[0].Path);

                for (int modeId = 0; modeId < area.Mode.Length; modeId++)
                {
                    ModeProperties mode = area.Mode[modeId];
                    if (mode?.Checkpoints == null)
                    {
                        continue;
                    }

                    foreach (CheckpointData checkpoint in mode.Checkpoints)
                    {
                        checkpoint.SetArea(area.ToKey((AreaMode)modeId));
                    }
                }
            }

            // Separate array as we sort it afterwards.
            List <AreaData> modAreas = new List <AreaData>();

            lock (Everest.Content.Map) {
                foreach (ModAsset asset in Everest.Content.Map.Values.Where(asset => asset.Type == typeof(AssetTypeMap)))
                {
                    string path = asset.PathVirtual.Substring(5);

                    AreaData area = new AreaData();

                    // Default values.

                    area.SetSID(path);
                    area.Name = path;
                    area.Icon = "areas/" + path.ToLowerInvariant();
                    if (!GFX.Gui.Has(area.Icon))
                    {
                        area.Icon = "areas/null";
                    }

                    area.Interlude    = false;
                    area.CanFullClear = true;

                    area.TitleBaseColor   = Calc.HexToColor("6c7c81");
                    area.TitleAccentColor = Calc.HexToColor("2f344b");
                    area.TitleTextColor   = Color.White;

                    area.IntroType = Player.IntroTypes.WakeUp;

                    area.Dreaming   = false;
                    area.ColorGrade = null;

                    area.Mode = new ModeProperties[] {
                        new ModeProperties {
                            Inventory  = PlayerInventory.Default,
                            AudioState = new AudioState(SFX.music_city, SFX.env_amb_00_main)
                        }
                    };

                    area.Wipe = (Scene scene, bool wipeIn, Action onComplete)
                                => new AngledWipe(scene, wipeIn, onComplete);

                    area.DarknessAlpha = 0.05f;
                    area.BloomBase     = 0f;
                    area.BloomStrength = 1f;

                    area.Jumpthru = "wood";

                    area.CassseteNoteColor = Calc.HexToColor("33a9ee");
                    area.CassetteSong      = SFX.cas_01_forsaken_city;

                    // Custom values can be set via the MapMeta.
                    MapMeta meta = new MapMeta();
                    meta.ApplyTo(area);
                    MapMeta metaLoaded = asset.GetMeta <MapMeta>();
                    if (metaLoaded != null)
                    {
                        area.SetMeta(null);
                        metaLoaded.ApplyTo(area);
                        meta = metaLoaded;
                    }

                    if (string.IsNullOrEmpty(area.Mode[0].Path))
                    {
                        area.Mode[0].Path = asset.PathVirtual.Substring(5);
                    }

                    // Some of the game's code checks for [1] / [2] explicitly.
                    // Let's just provide null modes to fill any gaps.
                    meta.Modes = meta.Modes ?? new MapMetaModeProperties[3];
                    if (meta.Modes.Length < 3)
                    {
                        MapMetaModeProperties[] larger = new MapMetaModeProperties[3];
                        for (int i = 0; i < meta.Modes.Length; i++)
                        {
                            larger[i] = meta.Modes[i];
                        }
                        meta.Modes = larger;
                    }
                    if (area.Mode.Length < 3)
                    {
                        ModeProperties[] larger = new ModeProperties[3];
                        for (int i = 0; i < area.Mode.Length; i++)
                        {
                            larger[i] = area.Mode[i];
                        }
                        area.Mode = larger;
                    }

                    // Celeste levelset always appears first.
                    if (area.GetLevelSet() == "Celeste")
                    {
                        Areas.Add(area);
                    }
                    else
                    {
                        modAreas.Add(area);
                    }

                    // Some special handling.
                    area.OnLevelBegin = (level) => {
                        MapMeta levelMeta = AreaData.Get(level.Session).GetMeta();
                        MapMetaModeProperties levelMetaMode = level.Session.MapData.GetMeta();

                        if (levelMetaMode?.SeekerSlowdown ?? false)
                        {
                            level.Add(new SeekerEffectsController());
                        }
                    };
                }
            }


            // Merge modAreas into Areas.
            Areas.AddRange(modAreas);

            // Find duplicates and remove any earlier copies.
            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area       = Areas[i];
                int      otherIndex = Areas.FindIndex(other => other.GetSID() == area.GetSID());
                if (otherIndex < i)
                {
                    Areas[otherIndex] = area;
                    Areas.RemoveAt(i);
                    i--;
                }
            }

            // Sort areas.
            Areas.Sort(AreaComparison);

            // Remove AreaDatas which are now a mode of another AreaData.
            // This can happen late as the map data (.bin) can contain additional metadata.
            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area       = Areas[i];
                string   path       = area.Mode[0].Path;
                int      otherIndex = Areas.FindIndex(other => other.Mode.Any(otherMode => otherMode?.Path == path));
                if (otherIndex != -1 && otherIndex != i)
                {
                    Areas.RemoveAt(i);
                    i--;
                    continue;
                }

                int?     order;
                AreaMode side;
                string   name;
                ParseName(path, out order, out side, out name);

                // Also check for .bins possibly belonging to A side .bins by their path and lack of existing modes.
                for (int ii = 0; ii < Areas.Count; ii++)
                {
                    AreaData other = Areas[ii];
                    int?     otherOrder;
                    AreaMode otherSide;
                    string   otherName;
                    ParseName(other.Mode[0].Path, out otherOrder, out otherSide, out otherName);

                    if (area.GetLevelSet() == other.GetLevelSet() && order == otherOrder && name == otherName && side != otherSide &&
                        !other.HasMode(side))
                    {
                        if (other.Mode[(int)side] == null)
                        {
                            other.Mode[(int)side] = new ModeProperties {
                                Inventory  = PlayerInventory.Default,
                                AudioState = new AudioState(SFX.music_city, SFX.env_amb_00_main)
                            }
                        }
                        ;
                        other.Mode[(int)side].Path = path;
                        Areas.RemoveAt(i);
                        i--;
                        break;
                    }
                }
            }

            for (int i = 0; i < Areas.Count; i++)
            {
                AreaData area = Areas[i];
                area.ID = i;

                // Clean up non-existing modes.
                int modei = 0;
                for (; modei < area.Mode.Length; modei++)
                {
                    ModeProperties mode = area.Mode[modei];
                    if (mode == null || string.IsNullOrEmpty(mode.Path))
                    {
                        break;
                    }
                }
                Array.Resize(ref area.Mode, modei);

                Logger.Log("AreaData", $"{i}: {area.GetSID()} - {area.Mode.Length} sides");

                // Update old MapData areas and load any new areas.

                // Add the A side MapData or update its area key.
                if (area.Mode[0].MapData != null)
                {
                    area.Mode[0].MapData.Area = area.ToKey();
                }
                else
                {
                    area.Mode[0].MapData = new MapData(area.ToKey());
                }

                if (area.IsInterludeUnsafe())
                {
                    continue;
                }

                // A and (some) B sides have PoemIDs. Can be overridden via empty PoemID.
                if (area.Mode[0].PoemID == null)
                {
                    area.Mode[0].PoemID = area.GetSID().DialogKeyify() + "_A";
                }
                if (area.Mode.Length > 1 &&
                    area.Mode[1] != null &&
                    area.Mode[1].PoemID == null)
                {
                    area.Mode[1].PoemID = area.GetSID().DialogKeyify() + "_B";
                }

                // Update all other existing mode's area keys.
                for (int mode = 1; mode < area.Mode.Length; mode++)
                {
                    if (area.Mode[mode] == null)
                    {
                        continue;
                    }
                    if (area.Mode[mode].MapData != null)
                    {
                        area.Mode[mode].MapData.Area = area.ToKey((AreaMode)mode);
                    }
                    else
                    {
                        area.Mode[mode].MapData = new MapData(area.ToKey((AreaMode)mode));
                    }
                }
            }

            // Load custom mountains
            // This needs to be done after areas are loaded because it depends on the MapMeta
            MTNExt.LoadMod();
            MTNExt.LoadModData();
        }
示例#2
0
        public void ApplyTo(AreaData area)
        {
            if (!string.IsNullOrEmpty(Icon) && GFX.Gui.Has(Icon))
            {
                area.Icon = Icon;
            }

            if (Interlude != null)
            {
                area.Interlude = Interlude.Value;
            }

            if (CassetteCheckpointIndex != null)
            {
                area.CassetteCheckpointIndex = CassetteCheckpointIndex.Value;
            }

            if (!string.IsNullOrEmpty(TitleBaseColor))
            {
                area.TitleBaseColor = Calc.HexToColor(TitleBaseColor);
            }
            if (!string.IsNullOrEmpty(TitleAccentColor))
            {
                area.TitleAccentColor = Calc.HexToColor(TitleAccentColor);
            }
            if (!string.IsNullOrEmpty(TitleTextColor))
            {
                area.TitleTextColor = Calc.HexToColor(TitleTextColor);
            }

            if (IntroType != null)
            {
                area.IntroType = IntroType.Value;
            }

            if (Dreaming != null)
            {
                area.Dreaming = Dreaming.Value;
            }

            if (!string.IsNullOrEmpty(ColorGrade))
            {
                area.ColorGrade = ColorGrade;
            }

            if (!string.IsNullOrEmpty(Wipe))
            {
                Type            type = Assembly.GetEntryAssembly().GetType(Wipe);
                ConstructorInfo ctor = type?.GetConstructor(new Type[] { typeof(Scene), typeof(bool), typeof(Action) });
                if (type != null && ctor != null)
                {
                    area.Wipe = (scene, wipeIn, onComplete) => ctor.Invoke(new object[] { scene, wipeIn, onComplete });
                }
            }

            if (DarknessAlpha != null)
            {
                area.DarknessAlpha = DarknessAlpha.Value;
            }
            if (BloomBase != null)
            {
                area.BloomBase = BloomBase.Value;
            }
            if (BloomStrength != null)
            {
                area.BloomStrength = BloomStrength.Value;
            }

            if (!string.IsNullOrEmpty(Jumpthru))
            {
                area.Jumpthru = Jumpthru;
            }

            if (CoreMode != null)
            {
                area.CoreMode = CoreMode.Value;
            }

            if (!string.IsNullOrEmpty(CassetteNoteColor))
            {
                area.CassseteNoteColor = Calc.HexToColor(CassetteNoteColor);
            }
            if (!string.IsNullOrEmpty(CassetteSong))
            {
                area.CassetteSong = CassetteSong;
            }

            area.MountainIdle   = Mountain?.Idle?.Convert() ?? area.MountainIdle;
            area.MountainSelect = Mountain?.Select?.Convert() ?? area.MountainSelect;
            area.MountainZoom   = Mountain?.Zoom?.Convert() ?? area.MountainZoom;
            area.MountainCursor = Mountain?.Cursor?.ToVector3() ?? area.MountainCursor;
            area.MountainState  = Mountain?.State ?? area.MountainState;

            ModeProperties[] modes = area.Mode;
            area.Mode = Convert(Modes) ?? modes;
            if (modes != null)
            {
                for (int i = 0; i < area.Mode.Length && i < modes.Length; i++)
                {
                    if (area.Mode[i] == null)
                    {
                        area.Mode[i] = modes[i];
                    }
                }
            }

            MapMeta meta = area.GetMeta();

            if (meta == null)
            {
                area.SetMeta(this);
            }
            else
            {
                if (!string.IsNullOrEmpty(Parent))
                {
                    meta.Parent = Parent;
                }

                if (!string.IsNullOrEmpty(PostcardSoundID))
                {
                    meta.PostcardSoundID = PostcardSoundID;
                }

                if (!string.IsNullOrEmpty(ForegroundTiles))
                {
                    meta.ForegroundTiles = ForegroundTiles;
                }

                if (!string.IsNullOrEmpty(BackgroundTiles))
                {
                    meta.BackgroundTiles = BackgroundTiles;
                }

                if (!string.IsNullOrEmpty(AnimatedTiles))
                {
                    meta.AnimatedTiles = AnimatedTiles;
                }

                if (!string.IsNullOrEmpty(Sprites))
                {
                    meta.Sprites = Sprites;
                }

                if (!string.IsNullOrEmpty(Portraits))
                {
                    meta.Portraits = Portraits;
                }

                if (OverrideASideMeta != null)
                {
                    meta.OverrideASideMeta = OverrideASideMeta;
                }

                if ((Modes?.Length ?? 0) != 0 && Modes.Any(mode => mode != null))
                {
                    meta.Modes = Modes;
                }

                if (Mountain != null)
                {
                    meta.Mountain = Mountain;
                }

                if (CompleteScreen != null)
                {
                    meta.CompleteScreen = CompleteScreen;
                }

                if (LoadingVignetteScreen != null)
                {
                    meta.LoadingVignetteScreen = LoadingVignetteScreen;
                }

                if (LoadingVignetteText != null)
                {
                    meta.LoadingVignetteText = LoadingVignetteText;
                }

                if (CassetteModifier != null)
                {
                    meta.CassetteModifier = CassetteModifier;
                }
            }
        }
示例#3
0
        public static AreaKey GenerateMap(RandoSettings settings)
        {
            var lastarea = AreaData.Areas[AreaData.Areas.Count - 1];
            var newID    = AreaData.Areas.Count;

            if (lastarea.GetLevelSet() == "randomizer")
            {
                newID--;
            }

            var newArea = new AreaData {
                IntroType = Player.IntroTypes.WakeUp,
                Interlude = false,
                Dreaming  = false,
                ID        = newID,
                Name      = $"{settings.Seed}_{settings.Hash}",
                Mode      = new ModeProperties[3] {
                    new ModeProperties {
                        Inventory = settings.Dashes == NumDashes.Zero ? new PlayerInventory(0, true, true, false) :
                                    settings.Dashes == NumDashes.One ? PlayerInventory.Default :
                                    PlayerInventory.CH6End,
                    }, null, null
                },
                Icon                = AreaData.Areas[0].Icon,
                MountainIdle        = AreaData.Areas[0].MountainIdle,
                MountainZoom        = AreaData.Areas[0].MountainZoom,
                MountainState       = AreaData.Areas[0].MountainState,
                MountainCursor      = new Vector3(0, 100000, 0), // ???
                MountainSelect      = AreaData.Areas[0].MountainSelect,
                MountainCursorScale = AreaData.Areas[0].MountainCursorScale,
            };

            newArea.SetMeta(new Meta.MapMeta {
                Modes = new Meta.MapMetaModeProperties[] {
                    new Meta.MapMetaModeProperties {
                        HeartIsEnd = true,
                        //SeekerSlowdown = true,  // this doesn't do anything
                    },
                    null, null
                }
            });
            newArea.OnLevelBegin = (level) => {
                level.Add(new SeekerEffectsController());
            };

            newArea.SetSID($"randomizer/{newArea.Name}");
            if (lastarea.GetSID().StartsWith("randomizer/"))
            {
                AreaData.Areas[AreaData.Areas.Count - 1] = newArea;
            }
            else
            {
                // avert race condition
                RandoModule.AreaHandoff = newArea;
                while (RandoModule.AreaHandoff != null)
                {
                    Thread.Sleep(10);
                }
            }

            var key = new AreaKey(newArea.ID);

            var r = new RandoLogic(settings, key);

            newArea.Wipe = r.PickWipe();
            newArea.CompleteScreenName = r.PickCompleteScreen();
            newArea.CassetteSong       = r.PickCassetteAudio();
            newArea.Mode[0].AudioState = new AudioState(r.PickMusicAudio(), r.PickAmbienceAudio());
            newArea.Mode[0].MapData    = r.MakeMap();
            r.RandomizeDialog();

            Logger.Log("randomizer", $"new area {newArea.GetSID()}");

            return(key);
        }
示例#4
0
        public void ApplyTo(AreaData area)
        {
            if (!string.IsNullOrEmpty(Name))
            {
                area.Name = Name;
            }

            if (!string.IsNullOrEmpty(SID))
            {
                area.SetSID(SID);
            }

            if (!string.IsNullOrEmpty(Icon) && GFX.Gui.Has(Icon))
            {
                area.Icon = Icon;
            }

            area.Interlude = Interlude;
            if (!string.IsNullOrEmpty(CompleteScreenName))
            {
                area.CompleteScreenName = CompleteScreenName;
            }

            area.CassetteCheckpointIndex = CassetteCheckpointIndex;

            if (!string.IsNullOrEmpty(TitleBaseColor))
            {
                area.TitleBaseColor = Calc.HexToColor(TitleBaseColor);
            }
            if (!string.IsNullOrEmpty(TitleAccentColor))
            {
                area.TitleAccentColor = Calc.HexToColor(TitleAccentColor);
            }
            if (!string.IsNullOrEmpty(TitleTextColor))
            {
                area.TitleTextColor = Calc.HexToColor(TitleTextColor);
            }

            area.IntroType = IntroType;

            area.Dreaming = Dreaming;
            if (!string.IsNullOrEmpty(ColorGrade))
            {
                area.ColorGrade = ColorGrade;
            }

            ModeProperties[] modes = area.Mode;
            area.Mode = Convert(Modes) ?? modes;
            if (modes != null)
            {
                for (int i = 0; i < area.Mode.Length && i < modes.Length; i++)
                {
                    if (area.Mode[i] == null)
                    {
                        area.Mode[i] = modes[i];
                    }
                }
            }

            if (!string.IsNullOrEmpty(Wipe))
            {
                Type            type = Assembly.GetEntryAssembly().GetType(Wipe);
                ConstructorInfo ctor = type?.GetConstructor(new Type[] { typeof(Scene), typeof(bool), typeof(Action) });
                if (type != null && ctor != null)
                {
                    area.Wipe = (scene, wipeIn, onComplete) => ctor.Invoke(new object[] { scene, wipeIn, onComplete });
                }
            }

            area.DarknessAlpha = DarknessAlpha;
            area.BloomBase     = BloomBase;
            area.BloomStrength = BloomStrength;

            if (!string.IsNullOrEmpty(Jumpthru))
            {
                area.Jumpthru = Jumpthru;
            }

            area.CoreMode = CoreMode;

            if (!string.IsNullOrEmpty(CassetteNoteColor))
            {
                area.CassseteNoteColor = Calc.HexToColor(CassetteNoteColor);
            }
            if (!string.IsNullOrEmpty(CassetteSong))
            {
                area.CassetteSong = CassetteSong;
            }

            area.MountainIdle   = Mountain?.Idle?.Convert() ?? area.MountainIdle;
            area.MountainSelect = Mountain?.Select?.Convert() ?? area.MountainSelect;
            area.MountainZoom   = Mountain?.Zoom?.Convert() ?? area.MountainZoom;
            area.MountainCursor = Mountain?.Cursor?.ToVector3() ?? area.MountainCursor;
            area.MountainState  = Mountain?.State ?? area.MountainState;

            area.SetMeta(this);
        }
示例#5
0
        public static AreaKey GenerateMap(RandoSettings settings)
        {
            StringWriter builder = new StringWriter();

            builder.Write("Generating map with settings:\n");
            YamlHelper.Serializer.Serialize(builder, settings);
            Logger.Log("randomizer", builder.ToString());
            var newID = AreaData.Areas.Count;

            if (AreaData.Areas.Last().GetSID().StartsWith("randomizer/"))
            {
                newID--;
            }

            var newArea = new AreaData {
                IntroType = Player.IntroTypes.WakeUp,
                Interlude = false,
                Dreaming  = false,
                ID        = newID,
                Name      = $"{settings.Seed}_{settings.EndlessLevel}_{settings.Hash}",
                Mode      = new ModeProperties[3] {
                    new ModeProperties {
                        Inventory = settings.Dashes == NumDashes.Zero ? new PlayerInventory(0, true, false, false) :
                                    settings.Dashes == NumDashes.One ?  new PlayerInventory(1, true, false, false) :
                                    new PlayerInventory(2, true, false, false),
                    }, null, null
                },
                Icon                = AreaData.Areas[0].Icon,
                MountainIdle        = AreaData.Areas[0].MountainIdle,
                MountainZoom        = AreaData.Areas[0].MountainZoom,
                MountainState       = AreaData.Areas[0].MountainState,
                MountainCursor      = new Vector3(0, 100000, 0), // ???
                MountainSelect      = AreaData.Areas[0].MountainSelect,
                MountainCursorScale = AreaData.Areas[0].MountainCursorScale,
            };

            newArea.SetMeta(new Meta.MapMeta {
                Modes = new Meta.MapMetaModeProperties[] {
                    new Meta.MapMetaModeProperties {
                        HeartIsEnd = true,
                        //SeekerSlowdown = true,  // this doesn't do anything
                    },
                    null, null
                }
            });
            newArea.OnLevelBegin = (level) => {
                level.Add(new SeekerEffectsController());
            };
            var dyn = new DynData <AreaData>(newArea);

            dyn.Set <RandoSettings>("RandoSettings", settings.Copy());

            newArea.SetSID($"randomizer/{newArea.Name}");

            // avert race condition
            RandoModule.AreaHandoff = newArea;
            while (RandoModule.AreaHandoff != null)
            {
                Thread.Sleep(10);
            }

            // invalidate the MapEditor area key cache, as it will erroniously see a cache hit
            typeof(Editor.MapEditor).GetField("area", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, AreaKey.None);

            var key = new AreaKey(newArea.ID);

            int tryNum = 0;

            while (true)
            {
                try {
                    var r = new RandoLogic(settings, key, tryNum);

                    newArea.Mode[0].MapData    = r.MakeMap();
                    newArea.Wipe               = r.PickWipe();
                    newArea.CompleteScreenName = r.PickCompleteScreen();
                    newArea.CassetteSong       = r.PickCassetteAudio();
                    newArea.Mode[0].AudioState = new AudioState(r.PickMusicAudio(), r.PickAmbienceAudio());
                    if (settings.RandomColors)
                    {
                        newArea.BloomBase     = (float)Math.Pow(r.Random.NextFloat(), 5) * r.Random.NextFloat();
                        newArea.DarknessAlpha = r.Random.NextFloat() * (float)Math.Pow(r.Random.NextFloat(), 0.5) * (float)Math.Pow(r.Random.NextFloat(), 2) * 0.35f;
                        newArea.ColorGrade    = r.PickColorGrade();
                    }
                    r.RandomizeDialog();
                    break;
                } catch (RetryException) {
                    tryNum++;
                    if (tryNum >= 500)
                    {
                        throw new GenerationError("Cannot create map with these settings");
                    }
                    Logger.Log("randomizer", $"Too many retries ({tryNum}), starting again");
                }
            }

            Logger.Log("randomizer", $"new area {newArea.GetSID()}");

            return(key);
        }
示例#6
0
        public static AreaKey GenerateMap(RandoSettings settings)
        {
            var  lastarea = AreaData.Areas[AreaData.Areas.Count - 1];
            var  newID    = AreaData.Areas.Count;
            bool secondVerseSameAsTheFirst = lastarea.GetSID().StartsWith("randomizer/");

            if (secondVerseSameAsTheFirst)
            {
                newID--;
            }

            var newArea = new AreaData {
                IntroType = Player.IntroTypes.WakeUp,
                Interlude = false,
                Dreaming  = false,
                ID        = newID,
                Name      = $"{settings.Seed}_{settings.Hash}",
                Mode      = new ModeProperties[3] {
                    new ModeProperties {
                        Inventory = settings.Dashes == NumDashes.Zero ? new PlayerInventory(0, true, true, false) :
                                    settings.Dashes == NumDashes.One ? PlayerInventory.Default :
                                    PlayerInventory.CH6End,
                    }, null, null
                },
                Icon                = AreaData.Areas[0].Icon,
                MountainIdle        = AreaData.Areas[0].MountainIdle,
                MountainZoom        = AreaData.Areas[0].MountainZoom,
                MountainState       = AreaData.Areas[0].MountainState,
                MountainCursor      = new Vector3(0, 100000, 0), // ???
                MountainSelect      = AreaData.Areas[0].MountainSelect,
                MountainCursorScale = AreaData.Areas[0].MountainCursorScale,
            };

            newArea.SetMeta(new Meta.MapMeta {
                Modes = new Meta.MapMetaModeProperties[] {
                    new Meta.MapMetaModeProperties {
                        HeartIsEnd = true,
                        //SeekerSlowdown = true,  // this doesn't do anything
                    },
                    null, null
                }
            });
            newArea.OnLevelBegin = (level) => {
                level.Add(new SeekerEffectsController());
            };
            var dyn = new DynData <AreaData>(newArea);

            dyn.Set <RandoSettings>("RandoSettings", settings.Copy());

            newArea.SetSID($"randomizer/{newArea.Name}");
            if (secondVerseSameAsTheFirst)
            {
                AreaData.Areas[AreaData.Areas.Count - 1] = newArea;
                // invalidate the MapEditor area key cache, as it will erroniously see a cache hit
                typeof(Editor.MapEditor).GetField("area", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, AreaKey.None);
            }
            else
            {
                // avert race condition
                RandoModule.AreaHandoff = newArea;
                while (RandoModule.AreaHandoff != null)
                {
                    Thread.Sleep(10);
                }
            }

            var key = new AreaKey(newArea.ID);

            var r = new RandoLogic(settings, key);

            newArea.Mode[0].MapData    = r.MakeMap();
            newArea.Wipe               = r.PickWipe();
            newArea.CompleteScreenName = r.PickCompleteScreen();
            newArea.CassetteSong       = r.PickCassetteAudio();
            newArea.Mode[0].AudioState = new AudioState(r.PickMusicAudio(), r.PickAmbienceAudio());
            r.RandomizeDialog();

            Logger.Log("randomizer", $"new area {newArea.GetSID()}");

            return(key);
        }