示例#1
0
        /// <summary>
        /// Add an Enter and Leave handler, notifying the user that a relaunch is required to apply the changes.
        /// </summary>
        /// <param name="option">The input TextMenu.Item option.</param>
        /// <param name="containingMenu">The menu containing the TextMenu.Item option.</param>
        /// <param name="needsRelaunch">This method does nothing if this is set to false.</param>
        /// <returns>The passed option.</returns>
        public static TextMenu.Item NeedsRelaunch(this TextMenu.Item option, TextMenu containingMenu, bool needsRelaunch = true)
        {
            if (!needsRelaunch)
            {
                return(option);
            }

            // build the "Restart is required" text menu entry
            TextMenuExt.EaseInSubHeaderExt needsRelaunchText = new TextMenuExt.EaseInSubHeaderExt(Dialog.Clean("MODOPTIONS_NEEDSRELAUNCH"), false, containingMenu)
            {
                TextColor   = Color.OrangeRed,
                HeightExtra = 0f
            };

            List <TextMenu.Item> items = containingMenu.GetItems();

            if (items.Contains(option))
            {
                // insert the text after the option that needs relaunch.
                containingMenu.Insert(items.IndexOf(option) + 1, needsRelaunchText);
            }

            option.OnEnter += delegate {
                // make the description appear.
                needsRelaunchText.FadeVisible = true;
            };
            option.OnLeave += delegate {
                // make the description disappear.
                needsRelaunchText.FadeVisible = false;
            };

            return(option);
        }
示例#2
0
        /// <summary>
        /// Add an Enter and Leave handler, displaying a description if selected.
        /// </summary>
        /// <param name="option">The input TextMenu.Item option.</param>
        /// <param name="containingMenu">The menu containing the TextMenu.Item option.</param>
        /// <param name="description"></param>
        /// <returns>The passed option.</returns>
        public static TextMenu.Item AddDescription(this TextMenu.Item option, TextMenu containingMenu, string description)
        {
            // build the description menu entry
            TextMenuExt.EaseInSubHeaderExt descriptionText = new TextMenuExt.EaseInSubHeaderExt(description, false, containingMenu)
            {
                TextColor   = Color.Gray,
                HeightExtra = 0f
            };

            List <TextMenu.Item> items = containingMenu.GetItems();

            if (items.Contains(option))
            {
                // insert the description after the option.
                containingMenu.Insert(items.IndexOf(option) + 1, descriptionText);
            }

            option.OnEnter += delegate {
                // make the description appear.
                descriptionText.FadeVisible = true;
            };
            option.OnLeave += delegate {
                // make the description disappear.
                descriptionText.FadeVisible = false;
            };

            return(option);
        }
示例#3
0
        public override void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot)
        {
            base.CreateModMenuSection(menu, inGame, snapshot);

            // this could maybe be refactored into a helper function with some generics magic
            foreach (var item in menu.Items)
            {
                if (!(item is TextMenu.Button btn) || !btn.Label.StartsWith(Dialog.Clean("modoptions_bingoclient_playername")))
                {
                    continue;
                }

                var messageHeader = new TextMenuExt.EaseInSubHeaderExt(Dialog.Clean("modoptions_bingoclient_playername_about"), false, menu)
                {
                    HeightExtra = 17f,
                    Offset      = new Vector2(30, -5),
                };

                menu.Insert(menu.Items.IndexOf(item) + 1, messageHeader);
                btn.OnEnter = () => messageHeader.FadeVisible = true;
                btn.OnLeave = () => messageHeader.FadeVisible = false;
                break;
            }

            foreach (var item in menu.Items)
            {
                if (!(item is TextMenu.OnOff btn) || !btn.Label.StartsWith(Dialog.Clean("modoptions_bingoclient_claimassist")))
                {
                    continue;
                }

                var messageHeader = new TextMenuExt.EaseInSubHeaderExt(Dialog.Clean("modoptions_bingoclient_claimassist_about"), false, menu)
                {
                    HeightExtra = 17f,
                    Offset      = new Vector2(30, -5),
                };

                menu.Insert(menu.Items.IndexOf(item) + 1, messageHeader);
                btn.OnEnter = () => messageHeader.FadeVisible = true;
                btn.OnLeave = () => messageHeader.FadeVisible = false;
                break;
            }

            if (this.Password != null && !this.Connected)
            {
                var retryBtn = new TextMenu.Button(Dialog.Clean("modoptions_bingoclient_reconnect"));
                retryBtn.OnPressed = () => {
                    this.Connect();
                };
                menu.Add(retryBtn);
            }
            if (this.Connected)
            {
                var disconnectBtn = new TextMenu.Button(Dialog.Clean("modoptions_bingoclient_disconnect"));
                disconnectBtn.OnPressed = () => {
                    this.Disconnect();
                };
                menu.Add(disconnectBtn);
            }
        }
        public void CreateOpenBackupFolderEntry(TextMenu textMenu, bool inGame)
        {
            TextMenu.Item item = new TextMenu.Button(DialogId.Options.OpenBackupFolder.DialogClean())
                                 .Pressed(() => {
                try {
                    string backupPath = Modules.InfiniteBackups.BackupPath;
                    if (!Directory.Exists(backupPath))
                    {
                        Directory.CreateDirectory(backupPath);
                    }
                    Process.Start(backupPath);
                } catch (Exception err) {
                    LogUtil.Log("Open backup folder failed!", LogLevel.Warn);
                    err.LogDetailed();

                    TextMenu.Item openBackupFolder = menuItems[DialogId.Options.OpenBackupFolder];
                    TextMenu.Item openFailed       = menuItems[DialogId.Subtext.OpenBackupFolderFailed];
                    if (!textMenu.Items.Contains(openFailed))
                    {
                        textMenu.Insert(textMenu.IndexOf(openBackupFolder) + 1, openFailed);
                    }
                }
            });
            textMenu.Add(item);
            menuItems.Add(DialogId.Options.OpenBackupFolder, item);

            // split the string into multiple lines to prevent off-screen menus caused by long path
            string[] descriptionLines = string.Format(DialogId.Subtext.BackupLocation.DialogGet(), Path.GetFullPath(Modules.InfiniteBackups.BackupPath)).SplitIntoFixedLength(50);
            TextMenuExt.EaseInSubHeaderExt backupLocationSubtext = new TextMenuExt.EaseInSubHeaderExt(string.Join("\n", descriptionLines), false, textMenu)
            {
                TextColor = Color.Gray
            };
            // increase the height and make it vertical align
            backupLocationSubtext.HeightExtra = (backupLocationSubtext.Title.Split('\n').Length - 1) * ActiveFont.LineHeight * 0.6f;
            backupLocationSubtext.Offset      = new Vector2(0f, -Math.Max(0f, -16f + backupLocationSubtext.HeightExtra) + textMenu.ItemSpacing);
            textMenu.Add(backupLocationSubtext);

            TextMenuExt.EaseInSubHeaderExt openFailedSubtext = new TextMenuExt.EaseInSubHeaderExt(DialogId.Subtext.OpenBackupFolderFailed.DialogClean(), false, textMenu)
            {
                TextColor   = Color.OrangeRed,
                HeightExtra = 0f
            };

            item.OnEnter += delegate {
                openFailedSubtext.FadeVisible     = true;
                backupLocationSubtext.FadeVisible = true;
            };
            item.OnLeave += delegate {
                openFailedSubtext.FadeVisible     = false;
                backupLocationSubtext.FadeVisible = false;
            };

            menuItems.Add(DialogId.Subtext.BackupLocation, backupLocationSubtext);
            menuItems.Add(DialogId.Subtext.OpenBackupFolderFailed, openFailedSubtext);
        }
示例#5
0
        private void OnPause(Level level, TextMenu menu, bool minimal)
        {
            void tweakVariantsMenu(TextMenu.Button btn, int idx)
            {
                var messageHeader = new TextMenuExt.EaseInSubHeaderExt(Dialog.Clean("bingoclient_variants_warning"), false, menu)
                {
                    HeightExtra = 17f,
                    Offset      = new Vector2(30, -5),
                };

                var oldAction = btn.OnPressed;

                btn.OnPressed = () => {
                    this.ModSession.CheckpointStartedVariant = null;
                    oldAction?.Invoke();
                };
                btn.OnEnter = () => messageHeader.FadeVisible = true;
                btn.OnLeave = () => messageHeader.FadeVisible = false;

                menu.Insert(idx + 1, messageHeader);
            }

            for (int i = 0; i < menu.Items.Count; i++)
            {
                var item = menu.Items[i];
                if (!(item is TextMenu.Button btn))
                {
                    continue;
                }

                if (btn.Label == Dialog.Clean("menu_pause_variant") || btn.Label == Dialog.Clean("modoptions_extendedvariants_pausemenu_button"))
                {
                    tweakVariantsMenu(btn, i);
                }
            }
        }
示例#6
0
        private void ReloadMenu()
        {
            menu = new DisablableTextMenu {
                new TextMenu.Header(Dialog.Clean("MODOPTIONS_RANDOMIZER_HEADER"))
            };

            var hashtext = new TextMenuExt.EaseInSubHeaderExt("{hash}", true, menu)
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            void updateHashText()
            {
                hashtext.Title = "v" + RandoModule.Instance.Metadata.VersionString;
                if (Settings.SeedType == SeedType.Custom)
                {
                    hashtext.Title += " #" + Settings.Hash.ToString();
                }
            }

            updateHashText();

            var errortext = new TextMenuExt.EaseInSubHeaderExt("{error}", false, menu)
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            var seedbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEED") + ": " + Settings.Seed);

            seedbutton.Pressed(() => {
                Audio.Play(SFX.ui_main_savefile_rename_start);
                menu.SceneAs <Overworld>().Goto <UI.OuiTextEntry>().Init <OuiRandoSettings>(
                    Settings.Seed,
                    (v) => Settings.Seed = v,
                    RandoModule.MAX_SEED_CHARS
                    );
            });
            seedbutton.Visible = Settings.SeedType == SeedType.Custom;

            var seedtypetoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEEDTYPE"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEEDTYPE_" + Enum.GetNames(typeof(SeedType))[i].ToUpperInvariant()));
            }, 0, (int)SeedType.Last - 1, (int)Settings.SeedType).Change((i) => {
                Settings.SeedType  = (SeedType)i;
                seedbutton.Visible = Settings.SeedType == SeedType.Custom;
                // just in case...
                seedbutton.Label = Dialog.Clean("MODOPTIONS_RANDOMIZER_SEED") + ": " + Settings.Seed;
                updateHashText();
            });

            var mapbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER")).Pressed(() => {
                Audio.Play(SFX.ui_main_button_select);
                menu.SceneAs <Overworld>().Goto <OuiMapPicker>();
            });

            var mapcountlbl = new TextMenuExt.SubHeaderExt(Settings.LevelCount.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS"))
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            var logictoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_LOGIC"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_LOGIC_" + Enum.GetNames(typeof(LogicType))[i].ToUpperInvariant()));
            }, 0, (int)LogicType.Last - 1, (int)Settings.Algorithm).Change((i) => {
                Settings.Algorithm = (LogicType)i;
                updateHashText();
            });

            var lengthtoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_LENGTH"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_LENGTH_" + Enum.GetNames(typeof(MapLength))[i].ToUpperInvariant()));
            }, 0, (int)MapLength.Last - 1, (int)Settings.Length).Change((i) => {
                Settings.Length = (MapLength)i;
                updateHashText();
            });

            var numdashestoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_NUMDASHES"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_NUMDASHES_" + Enum.GetNames(typeof(NumDashes))[i].ToUpperInvariant()));
            }, 0, (int)NumDashes.Last - 1, (int)Settings.Dashes).Change((i) => {
                Settings.Dashes = (NumDashes)i;
                updateHashText();
            });

            var difficultytoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTY"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTY_" + Enum.GetNames(typeof(Difficulty))[i].ToUpperInvariant()));
            }, 0, (int)Difficulty.Last - 1, (int)Settings.Difficulty).Change((i) => {
                Settings.Difficulty = (Difficulty)i;
                updateHashText();
            });

            var repeatroomstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_REPEATROOMS"), Settings.RepeatRooms).Change((val) => {
                Settings.RepeatRooms = val;
                updateHashText();
            });

            var enterunknowntext = new TextMenuExt.EaseInSubHeaderExt(Dialog.Clean("MODOPTIONS_RANDOMIZER_ENTERUNKNOWN_EXPLAIN"), false, menu)
            {
                HeightExtra = 17f,
                Offset      = new Vector2(30, -5),
            };

            var enterunknowntoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_ENTERUNKNOWN"), Settings.EnterUnknown).Change((val) => {
                Settings.EnterUnknown = val;
                updateHashText();
            });

            enterunknowntoggle.OnEnter += () => { enterunknowntext.FadeVisible = true; };
            enterunknowntoggle.OnLeave += () => { enterunknowntext.FadeVisible = false; };

            var shinetoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_SHINE"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_SHINE_" + Enum.GetNames(typeof(ShineLights))[i].ToUpperInvariant()));
            }, 0, (int)ShineLights.Last - 1, (int)Settings.Lights).Change((i) => {
                Settings.Lights = (ShineLights)i;
                updateHashText();
            });

            var darktoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_DARK"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_DARK_" + Enum.GetNames(typeof(Darkness))[i].ToUpperInvariant()));
            }, 0, (int)Darkness.Last - 1, (int)Settings.Darkness).Change((i) => {
                Settings.Darkness = (Darkness)i;
                updateHashText();
            });

            var goldentoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_GOLDENBERRY"), Settings.SpawnGolden).Change((val) => {
                Settings.SpawnGolden = val;
            });

            var moreoptions = false;

            repeatroomstoggle.Visible  = false;
            enterunknowntoggle.Visible = false;
            goldentoggle.Visible       = false;
            shinetoggle.Visible        = false;
            darktoggle.Visible         = false;

            var moreoptionsbtn = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MOREOPTIONS"));

            moreoptionsbtn.Pressed(() => {
                moreoptions          = !moreoptions;
                moreoptionsbtn.Label = moreoptions ? Dialog.Clean("MODOPTIONS_RANDOMIZER_FEWEROPTIONS") : Dialog.Clean("MODOPTIONS_RANDOMIZER_MOREOPTIONS");

                repeatroomstoggle.Visible  = moreoptions;
                enterunknowntoggle.Visible = moreoptions;
                goldentoggle.Visible       = moreoptions;
                shinetoggle.Visible        = moreoptions;
                darktoggle.Visible         = moreoptions;
            });

            void syncModel()
            {
                repeatroomstoggle.Index  = Settings.RepeatRooms ? 1 : 0;
                enterunknowntoggle.Index = Settings.EnterUnknown ? 1 : 0;
                logictoggle.Index        = (int)Settings.Algorithm;
                lengthtoggle.Index       = (int)Settings.Length;
                numdashestoggle.Index    = (int)Settings.Dashes;
                difficultytoggle.Index   = (int)Settings.Difficulty;
                shinetoggle.Index        = (int)Settings.Lights;
                darktoggle.Index         = (int)Settings.Darkness;
                mapcountlbl.Title        = Settings.LevelCount.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS");

                var locked = Settings.Rules != Ruleset.Custom;

                mapbutton.Disabled          = locked;
                repeatroomstoggle.Disabled  = locked;
                enterunknowntoggle.Disabled = locked;
                logictoggle.Disabled        = locked;
                lengthtoggle.Disabled       = locked;
                numdashestoggle.Disabled    = locked;
                difficultytoggle.Disabled   = locked;
                shinetoggle.Disabled        = locked;
                darktoggle.Disabled         = locked;
            }

            syncModel();

            var rulestoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_RULES"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_RULES_" + Enum.GetNames(typeof(Ruleset))[i].ToUpperInvariant()));
            }, 0, (int)Ruleset.Last - 1, (int)Settings.Rules).Change((i) => {
                Settings.Rules = (Ruleset)i;
                Settings.Enforce();
                syncModel();
                updateHashText();
            });

            var startbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_START"));

            startbutton.Pressed(() => {
                if (this.entering)
                {
                    return;
                }

                void reenableMenu()
                {
                    this.builderThread = null;

                    startbutton.Label = Dialog.Clean("MODOPTIONS_RANDOMIZER_START");
                    updateHashText();
                    menu.DisableMovement = false;
                }

                if (this.builderThread == null)
                {
                    errortext.FadeVisible = false;
                    startbutton.Label     = Dialog.Clean("MODOPTIONS_RANDOMIZER_CANCEL");
                    hashtext.Title       += " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_GENERATING");
                    menu.DisableMovement  = true;

                    this.builderThread = new Thread(() => {
                        Settings.Enforce();
                        AreaKey newArea;
                        try {
                            newArea = RandoLogic.GenerateMap(Settings);
                        } catch (ThreadAbortException) {
                            return;
                        } catch (Exception e) {
                            if (e.Message == "Could not generate map")
                            {
                                errortext.Title = e.Message;
                            }
                            else
                            {
                                errortext.Title = "Encountered an error - Check log.txt for details";
                                Logger.LogDetailed(e, "randomizer");
                            }
                            errortext.FadeVisible = true;
                            reenableMenu();
                            return;
                        }
                        this.entering = true;

                        Audio.SetMusic((string)null, true, true);
                        Audio.SetAmbience((string)null, true);
                        Audio.Play("event:/ui/main/savefile_begin");

                        // use the debug file
                        SaveData.InitializeDebugMode();
                        // turn on variants mode
                        SaveData.Instance.VariantMode = true;
                        SaveData.Instance.AssistMode  = false;
                        // clear summit gems, just in case!
                        SaveData.Instance.SummitGems = new bool[6];
                        // mark as completed to spawn golden berry
                        SaveData.Instance.Areas[newArea.ID].Modes[0].Completed = true;

                        var fade = new FadeWipe(this.Scene, false, () => {   // assign to variable to suppress compiler warning
                            var session = new Session(newArea, null, null);
                            //session.FirstLevel = false;   // setting this value here prevents the wakeup animation. set it in a hook.
                            LevelEnter.Go(session, true);
                            this.builderThread = null;
                            this.entering      = false;
                        });

                        /*foreach (AreaData area in AreaData.Areas) {
                         *  Logger.Log("randomizer", $"Skeleton for {area.GetSID()}");
                         *  RandoConfigFile.YamlSkeleton(area);
                         *
                         * }*/
                    });
                    this.builderThread.Start();
                }
                else
                {
                    this.builderThread.Abort();
                    reenableMenu();
                }
            });

            menu.Add(seedtypetoggle);
            menu.Add(seedbutton);
            menu.Add(rulestoggle);
            menu.Add(mapbutton);
            menu.Add(mapcountlbl);
            menu.Add(logictoggle);
            menu.Add(lengthtoggle);
            menu.Add(numdashestoggle);
            menu.Add(difficultytoggle);
            menu.Add(moreoptionsbtn);
            menu.Add(repeatroomstoggle);
            menu.Add(enterunknowntoggle);
            menu.Add(enterunknowntext);
            menu.Add(shinetoggle);
            menu.Add(darktoggle);
            menu.Add(goldentoggle);
            menu.Add(startbutton);
            menu.Add(hashtext);
            menu.Add(errortext);

            Scene.Add(menu);
        }
示例#7
0
        private void ReloadMenu()
        {
            menu = new DisablableTextMenu {
                new TextMenu.Header(Dialog.Clean("MODOPTIONS_RANDOMIZER_HEADER"))
            };

            var hashtext = new TextMenuExt.EaseInSubHeaderExt("{hash}", true, menu)
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            void updateHashText()
            {
                hashtext.Title = "v" + RandoModule.Instance.Metadata.VersionString;
                if (Settings.SeedType == SeedType.Custom)
                {
                    hashtext.Title += " #" + Settings.Hash.ToString();
                }
            }

            updateHashText();

            var errortext = new TextMenuExt.EaseInSubHeaderExt("{error}", false, menu)
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            var seedbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEED") + ": " + Settings.Seed);

            seedbutton.Pressed(() => {
                Audio.Play(SFX.ui_main_savefile_rename_start);
                menu.SceneAs <Overworld>().Goto <UI.OuiTextEntry>().Init <OuiRandoSettings>(
                    Settings.Seed,
                    (v) => Settings.Seed = v,
                    RandoModule.MAX_SEED_CHARS
                    );
            });
            seedbutton.Visible = Settings.SeedType == SeedType.Custom;

            var seedtypetoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEEDTYPE"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEEDTYPE_" + Enum.GetNames(typeof(SeedType))[i].ToUpperInvariant()));
            }, 0, (int)SeedType.Last - 1, (int)Settings.SeedType).Change((i) => {
                Settings.SeedType  = (SeedType)i;
                seedbutton.Visible = Settings.SeedType == SeedType.Custom;
                // just in case...
                seedbutton.Label = Dialog.Clean("MODOPTIONS_RANDOMIZER_SEED") + ": " + Settings.Seed;
                updateHashText();
            });

            var mapbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER")).Pressed(() => {
                Audio.Play(SFX.ui_main_button_select);
                menu.SceneAs <Overworld>().Goto <OuiMapPicker>();
            });

            var mapcountlbl = new TextMenuExt.SubHeaderExt(Settings.LevelCount.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS"))
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            var logictoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_LOGIC"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_LOGIC_" + Enum.GetNames(typeof(LogicType))[i].ToUpperInvariant()));
            }, 0, (int)LogicType.Last - 1, (int)Settings.Algorithm).Change((i) => {
                Settings.Algorithm = (LogicType)i;
                updateHashText();
            });

            var lengthtoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_LENGTH"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_LENGTH_" + Enum.GetNames(typeof(MapLength))[i].ToUpperInvariant()));
            }, 0, (int)MapLength.Last - 1, (int)Settings.Length).Change((i) => {
                Settings.Length = (MapLength)i;
                updateHashText();
            });

            var numdashestoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_NUMDASHES"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_NUMDASHES_" + Enum.GetNames(typeof(NumDashes))[i].ToUpperInvariant()));
            }, 0, (int)NumDashes.Last - 1, (int)Settings.Dashes).Change((i) => {
                Settings.Dashes = (NumDashes)i;
                updateHashText();
            });

            var difficultytoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTY"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTY_" + Enum.GetNames(typeof(Difficulty))[i].ToUpperInvariant()));
            }, 0, (int)Difficulty.Last - 1, (int)Settings.Difficulty).Change((i) => {
                Settings.Difficulty = (Difficulty)i;
                updateHashText();
            });

            var repeatroomstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_REPEATROOMS"), Settings.RepeatRooms).Change((val) => {
                Settings.RepeatRooms = val;
                updateHashText();
            });

            var enterunknowntext = new TextMenuExt.EaseInSubHeaderExt(Dialog.Clean("MODOPTIONS_RANDOMIZER_ENTERUNKNOWN_EXPLAIN"), false, menu)
            {
                HeightExtra = 17f,
                Offset      = new Vector2(30, -5),
            };

            var enterunknowntoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_ENTERUNKNOWN"), Settings.EnterUnknown).Change((val) => {
                Settings.EnterUnknown = val;
                updateHashText();
            });

            enterunknowntoggle.OnEnter += () => { enterunknowntext.FadeVisible = true; };
            enterunknowntoggle.OnLeave += () => { enterunknowntext.FadeVisible = false; };

            var shinetoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_SHINE"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_SHINE_" + Enum.GetNames(typeof(ShineLights))[i].ToUpperInvariant()));
            }, 0, (int)ShineLights.Last - 1, (int)Settings.Lights).Change((i) => {
                Settings.Lights = (ShineLights)i;
                updateHashText();
            });

            var darktoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_DARK"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_DARK_" + Enum.GetNames(typeof(Darkness))[i].ToUpperInvariant()));
            }, 0, (int)Darkness.Last - 1, (int)Settings.Darkness).Change((i) => {
                Settings.Darkness = (Darkness)i;
                updateHashText();
            });

            var goldentoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_GOLDENBERRY"), Settings.SpawnGolden).Change((val) => {
                Settings.SpawnGolden = val;
            });

            var variantstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_VARIANTS"), Settings.Variants).Change((val) => {
                Settings.Variants = val;
            });

            var decorationstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_DECORATIONS"), Settings.RandomDecorations).Change((val) => {
                Settings.RandomDecorations = val;
            });

            var moreoptions = false;

            repeatroomstoggle.Visible  = false;
            enterunknowntoggle.Visible = false;
            goldentoggle.Visible       = false;
            shinetoggle.Visible        = false;
            darktoggle.Visible         = false;
            variantstoggle.Visible     = false;
            decorationstoggle.Visible  = false;

            var moreoptionsbtn = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MOREOPTIONS"));

            moreoptionsbtn.Pressed(() => {
                moreoptions          = !moreoptions;
                moreoptionsbtn.Label = moreoptions ? Dialog.Clean("MODOPTIONS_RANDOMIZER_FEWEROPTIONS") : Dialog.Clean("MODOPTIONS_RANDOMIZER_MOREOPTIONS");

                repeatroomstoggle.Visible  = moreoptions;
                enterunknowntoggle.Visible = moreoptions;
                goldentoggle.Visible       = moreoptions;
                shinetoggle.Visible        = moreoptions;
                darktoggle.Visible         = moreoptions;
                variantstoggle.Visible     = moreoptions;
                decorationstoggle.Visible  = moreoptions;
            });

            void syncModel()
            {
                repeatroomstoggle.Index  = Settings.RepeatRooms ? 1 : 0;
                enterunknowntoggle.Index = Settings.EnterUnknown ? 1 : 0;
                variantstoggle.Index     = Settings.Variants ? 1 : 0;
                logictoggle.Index        = (int)Settings.Algorithm;
                lengthtoggle.Index       = (int)Settings.Length;
                numdashestoggle.Index    = (int)Settings.Dashes;
                difficultytoggle.Index   = (int)Settings.Difficulty;
                shinetoggle.Index        = (int)Settings.Lights;
                darktoggle.Index         = (int)Settings.Darkness;
                mapcountlbl.Title        = Settings.LevelCount.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS");

                var locked = Settings.Rules != Ruleset.Custom;

                mapbutton.Disabled          = locked;
                repeatroomstoggle.Disabled  = locked;
                enterunknowntoggle.Disabled = locked;
                logictoggle.Disabled        = locked;
                lengthtoggle.Disabled       = locked;
                numdashestoggle.Disabled    = locked;
                difficultytoggle.Disabled   = locked;
                shinetoggle.Disabled        = locked;
                darktoggle.Disabled         = locked;
                variantstoggle.Disabled     = locked;
            }

            syncModel();

            var rulestoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_RULES"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_RULES_" + Enum.GetNames(typeof(Ruleset))[i].ToUpperInvariant()));
            }, 0, (int)Ruleset.Last - 1, (int)Settings.Rules).Change((i) => {
                Settings.Rules = (Ruleset)i;
                Settings.Enforce();
                syncModel();
                updateHashText();
            });

            var startbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_START"));

            startbutton.Pressed(() => {
                if (this.entering)
                {
                    return;
                }

                void reenableMenu()
                {
                    this.builderThread = null;

                    startbutton.Label = Dialog.Clean("MODOPTIONS_RANDOMIZER_START");
                    updateHashText();
                    menu.DisableMovement = false;
                }

                if (this.builderThread == null)
                {
                    errortext.FadeVisible = false;
                    startbutton.Label     = Dialog.Clean("MODOPTIONS_RANDOMIZER_CANCEL");
                    hashtext.Title       += " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_GENERATING");
                    menu.DisableMovement  = true;

                    this.builderThread = new Thread(() => {
                        Settings.Enforce();
                        AreaKey newArea;
                        try {
                            newArea = RandoLogic.GenerateMap(Settings);
                        } catch (ThreadAbortException) {
                            return;
                        } catch (GenerationError e) {
                            errortext.Title       = e.Message;
                            errortext.FadeVisible = true;
                            reenableMenu();
                            return;
                        } catch (Exception e) {
                            errortext.Title = "Encountered an error - Check log.txt for details";
                            Logger.LogDetailed(e, "randomizer");
                            errortext.FadeVisible = true;
                            reenableMenu();
                            return;
                        }
                        // save settings
                        RandoModule.Instance.SavedData.SavedSettings = Settings.Copy();
                        RandoModule.Instance.SaveSettings();

                        this.entering       = true;
                        RandoModule.StartMe = newArea;
                        while (RandoModule.StartMe != null)
                        {
                            Thread.Sleep(10);
                        }
                        this.builderThread = null;
                        this.entering      = false;
                    });
                    this.builderThread.Start();
                }
                else
                {
                    this.builderThread.Abort();
                    reenableMenu();
                }
            });

            menu.Add(seedtypetoggle);
            menu.Add(seedbutton);
            menu.Add(rulestoggle);
            menu.Add(mapbutton);
            menu.Add(mapcountlbl);
            menu.Add(logictoggle);
            menu.Add(lengthtoggle);
            menu.Add(numdashestoggle);
            menu.Add(difficultytoggle);
            menu.Add(moreoptionsbtn);
            menu.Add(repeatroomstoggle);
            menu.Add(enterunknowntoggle);
            menu.Add(enterunknowntext);
            menu.Add(shinetoggle);
            menu.Add(darktoggle);
            menu.Add(goldentoggle);
            menu.Add(variantstoggle);
            menu.Add(decorationstoggle);
            menu.Add(startbutton);
            menu.Add(hashtext);
            menu.Add(errortext);

            Scene.Add(menu);
        }
        protected override Entity ReloadMenu()
        {
            var menu = new DisablableTextMenu {
                new TextMenu.Header(Dialog.Clean("MODOPTIONS_RANDOMIZER_HEADER"))
            };

            var currentPage = OptionsPages.Basic;
            var pages       = new[] { new List <TextMenu.Item>(), new List <TextMenu.Item>(), new List <TextMenu.Item>(), new List <TextMenu.Item>(), new List <TextMenu.Item>() };

            var hashtext = new TextMenuExt.EaseInSubHeaderExt("{hash}", true, menu)
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            void updateHashText()
            {
                hashtext.Title = "v" + RandoModule.Instance.VersionString;
                if (Settings.SeedType == SeedType.Custom)
                {
                    hashtext.Title += " #" + Settings.Hash.ToString();
                }
            }

            updateHashText();

            var errortext = new TextMenuExt.EaseInSubHeaderExt("{error}", false, menu)
            {
                HeightExtra = -10f,
                Offset      = new Vector2(30, -5),
            };

            var seedbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEED") + ": " + Settings.Seed);

            seedbutton.Pressed(() => {
                Audio.Play(SFX.ui_main_savefile_rename_start);
                menu.SceneAs <Overworld>().Goto <UI.OuiTextEntry>().Init <OuiRandoSettings>(
                    Settings.Seed,
                    (v) => Settings.Seed = v,
                    RandoModule.MAX_SEED_CHARS
                    );
            });
            pages[1].Add(seedbutton);

            var seedtypetoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEEDTYPE"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_SEEDTYPE_" + Enum.GetNames(typeof(SeedType))[i].ToUpperInvariant()));
            }, 0, (int)SeedType.Last - 1, (int)Settings.SeedType).Change((i) => {
                Settings.SeedType  = (SeedType)i;
                seedbutton.Visible = Settings.SeedType == SeedType.Custom;
                // just in case...
                seedbutton.Label = Dialog.Clean("MODOPTIONS_RANDOMIZER_SEED") + ": " + Settings.Seed;
                updateHashText();
            });

            pages[1].Add(seedtypetoggle);

            var lengthtoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_LENGTH"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_LENGTH_" + Enum.GetNames(typeof(MapLength))[i].ToUpperInvariant()));
            }, 0, (int)MapLength.Last - 1, (int)Settings.Length).Change((i) => {
                Settings.Length = (MapLength)i;
                updateHashText();
            });

            pages[1].Add(lengthtoggle);

            var numdashestoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_NUMDASHES"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_NUMDASHES_" + Enum.GetNames(typeof(NumDashes))[i].ToUpperInvariant()));
            }, 0, (int)NumDashes.Last - 1, (int)Settings.Dashes).Change((i) => {
                Settings.Dashes = (NumDashes)i;
                updateHashText();
            });

            pages[1].Add(numdashestoggle);

            var endlesslivespicker = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_LIVES"), i => {
                return(i == 0 ? Dialog.Clean("MODOPTIONS_RANDOMIZER_LIVES_INFINITE") : i.ToString());
            }, 0, 50, Settings.EndlessLives);

            endlesslivespicker.OnValueChange = i => {
                Settings.EndlessLives = i;
            };
            endlesslivespicker.Visible = Settings.Algorithm == LogicType.Endless;

            var logictoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_LOGIC"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_LOGIC_" + Enum.GetNames(typeof(LogicType))[i].ToUpperInvariant()));
            }, 0, (int)LogicType.Last - 1, (int)Settings.Algorithm).Change((i) => {
                Settings.Algorithm         = (LogicType)i;
                endlesslivespicker.Visible = Settings.Algorithm == LogicType.Endless;
                updateHashText();
            });

            pages[1].Add(logictoggle);
            pages[1].Add(endlesslivespicker);

            var difficultytoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTY"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTY_" + Enum.GetNames(typeof(Difficulty))[i].ToUpperInvariant()));
            }, 0, (int)Difficulty.Last - 1, (int)Settings.Difficulty).Change((i) => {
                Settings.Difficulty = (Difficulty)i;
                updateHashText();
            });

            pages[1].Add(difficultytoggle);

            var mapinfo = this.MakeMapPicker(updateHashText);

            pages[2].AddRange(mapinfo.Item1);

            var strawberriestoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_STRAWBERRIES"), i => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_STRAWBERRIES_" + Enum.GetNames(typeof(StrawberryDensity))[i].ToUpperInvariant()));
            }, 0, (int)StrawberryDensity.Last - 1, (int)Settings.Strawberries).Change(i => {
                Settings.Strawberries = (StrawberryDensity)i;
                updateHashText();
            });

            pages[3].Add(strawberriestoggle);

            var difficultycurvetoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTYCURVE"), i => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_DIFFICULTYCURVE_" + Enum.GetNames(typeof(DifficultyEagerness))[i].ToUpperInvariant()));
            }, 0, (int)DifficultyEagerness.Last - 1, (int)Settings.DifficultyEagerness).Change(i => {
                Settings.DifficultyEagerness = (DifficultyEagerness)i;
                updateHashText();
            });

            pages[3].Add(difficultycurvetoggle);

            var repeatroomstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_REPEATROOMS"), Settings.RepeatRooms).Change((val) => {
                Settings.RepeatRooms = val;
                updateHashText();
            });

            pages[3].Add(repeatroomstoggle);

            var enterunknowntoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_ENTERUNKNOWN"), Settings.EnterUnknown).Change((val) => {
                Settings.EnterUnknown = val;
                updateHashText();
            });

            pages[3].Add(enterunknowntoggle);

            var goldentoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_GOLDENBERRY"), Settings.SpawnGolden).Change((val) => {
                Settings.SpawnGolden = val;
            });

            pages[3].Add(goldentoggle);

            var variantstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_VARIANTS"), Settings.Variants).Change((val) => {
                Settings.Variants = val;
            });

            pages[3].Add(variantstoggle);

            var shinetoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_SHINE"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_SHINE_" + Enum.GetNames(typeof(ShineLights))[i].ToUpperInvariant()));
            }, 0, (int)ShineLights.Last - 1, (int)Settings.Lights).Change((i) => {
                Settings.Lights = (ShineLights)i;
                updateHashText();
            });

            pages[4].Add(shinetoggle);

            var darktoggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_DARK"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_DARK_" + Enum.GetNames(typeof(Darkness))[i].ToUpperInvariant()));
            }, 0, (int)Darkness.Last - 1, (int)Settings.Darkness).Change((i) => {
                Settings.Darkness = (Darkness)i;
                updateHashText();
            });

            pages[4].Add(darktoggle);

            var decorationstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_DECORATIONS"), Settings.RandomDecorations).Change((val) => {
                Settings.RandomDecorations = val;
            });

            pages[4].Add(decorationstoggle);

            var colorstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_COLORS"), Settings.RandomColors).Change((val) => {
                Settings.RandomColors = val;
            });

            pages[4].Add(colorstoggle);

            var bgstoggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_RANDOMIZER_BACKGROUNDS"), Settings.RandomBackgrounds).Change((val) => {
                Settings.RandomBackgrounds = val;
            });

            pages[4].Add(bgstoggle);

            var rulestoggles = new Dictionary <String, TextMenuExt.ButtonExt>();

            void syncModel()
            {
                repeatroomstoggle.Index     = Settings.RepeatRooms ? 1 : 0;
                enterunknowntoggle.Index    = Settings.EnterUnknown ? 1 : 0;
                variantstoggle.Index        = Settings.Variants ? 1 : 0;
                logictoggle.Index           = (int)Settings.Algorithm;
                lengthtoggle.Index          = (int)Settings.Length;
                numdashestoggle.Index       = (int)Settings.Dashes;
                difficultytoggle.Index      = (int)Settings.Difficulty;
                difficultycurvetoggle.Index = (int)Settings.DifficultyEagerness;
                shinetoggle.Index           = (int)Settings.Lights;
                darktoggle.Index            = (int)Settings.Darkness;
                endlesslivespicker.Index    = Settings.EndlessLives;
                strawberriestoggle.Index    = (int)Settings.Strawberries;

                var locked = !String.IsNullOrEmpty(Settings.Rules);

                foreach (var item in pages[2])
                {
                    item.Disabled = locked;
                }
                repeatroomstoggle.Disabled     = locked;
                enterunknowntoggle.Disabled    = locked;
                logictoggle.Disabled           = locked;
                lengthtoggle.Disabled          = locked;
                numdashestoggle.Disabled       = locked;
                difficultytoggle.Disabled      = locked;
                difficultycurvetoggle.Disabled = locked;
                shinetoggle.Disabled           = locked;
                darktoggle.Disabled            = locked;
                variantstoggle.Disabled        = locked;
                endlesslivespicker.Disabled    = locked;
                strawberriestoggle.Disabled    = locked;

                var i = (OptionsPages)0;

                foreach (var page in pages)
                {
                    var visible = i == currentPage;
                    foreach (var widget in page)
                    {
                        widget.Visible = visible;
                    }
                    i++;
                }
                endlesslivespicker.Visible &= Settings.Algorithm == LogicType.Endless;
                seedbutton.Visible         &= Settings.SeedType == SeedType.Custom;

                foreach (var kv in rulestoggles)
                {
                    //kv.Value.Visible &= kv.Key == "" || RandoModule.Instance.MetaConfig.RulesetsDict[kv.Key].Algorithm == this.Settings.Algorithm;
                    kv.Value.Icon = kv.Key == this.Settings.Rules ? "menu/poemarrow" : "";
                }

                mapinfo.Item2();
            }

            var pageToggle = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_RANDOMIZER_OPTIONS"), (i) => {
                return(Dialog.Clean("MODOPTIONS_RANDOMIZER_OPTIONS_" + Enum.GetNames(typeof(OptionsPages))[i].ToUpperInvariant()));
            }, 0, (int)OptionsPages.Last - 1, (int)currentPage).Change((i) => {
                currentPage = (OptionsPages)i;
                syncModel();
                menu.RecalculateSize();
                menu.Position.Y = menu.ScrollTargetY;
            });

            void syncRuleset()
            {
                Settings.Enforce();
                syncModel();
                updateHashText();
            }

            var nullToggle = new TextMenuExt.ButtonExt(Dialog.Clean("MODOPTIONS_RANDOMIZER_RULES_CUSTOM"));

            nullToggle.Pressed(this.MakeRulesetToggler("", syncRuleset));
            rulestoggles.Add("", nullToggle);
            pages[0].Add(nullToggle);

            var sortedrules = new List <RandoMetadataRuleset>(RandoModule.Instance.MetaConfig.Rulesets);

            sortedrules.Sort((a, b) => a.Name.CompareTo(b.Name));
            foreach (var ruleset in sortedrules)
            {
                var toggle = new TextMenuExt.ButtonExt(ruleset.LongName);
                toggle.Pressed(this.MakeRulesetToggler(ruleset.Name, syncRuleset));
                rulestoggles.Add(ruleset.Name, toggle);
                pages[0].Add(toggle);
            }

            var startbutton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_START"));

            startbutton.Pressed(() => {
                if (this.Entering)
                {
                    return;
                }

                void reenableMenu()
                {
                    this.BuilderThread = null;

                    startbutton.Label = Dialog.Clean("MODOPTIONS_RANDOMIZER_START");
                    updateHashText();
                    menu.DisableMovement = false;
                }

                if (this.BuilderThread == null)
                {
                    errortext.FadeVisible = false;
                    startbutton.Label     = Dialog.Clean("MODOPTIONS_RANDOMIZER_CANCEL");
                    hashtext.Title       += " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_GENERATING");
                    menu.DisableMovement  = true;

                    this.BuilderThread = new Thread(() => {
                        Settings.Enforce();
                        AreaKey newArea;
                        try {
                            newArea = RandoLogic.GenerateMap(Settings);
                        } catch (ThreadAbortException) {
                            return;
                        } catch (GenerationError e) {
                            errortext.Title       = e.Message;
                            errortext.FadeVisible = true;
                            reenableMenu();
                            return;
                        } catch (Exception e) {
                            errortext.Title = "Encountered an error - Check log.txt for details";
                            Logger.LogDetailed(e, "randomizer");
                            errortext.FadeVisible = true;
                            reenableMenu();
                            return;
                        }
                        // save settings
                        RandoModule.Instance.SavedData.SavedSettings = Settings.Copy();
                        RandoModule.Instance.SaveSettings();

                        this.Entering       = true;
                        RandoModule.StartMe = newArea;
                        while (RandoModule.StartMe != null)
                        {
                            Thread.Sleep(10);
                        }
                        this.BuilderThread = null;
                        this.Entering      = false;
                    });
                    this.BuilderThread.Start();
                }
                else
                {
                    this.BuilderThread.Abort();
                    reenableMenu();
                }
            });

            menu.Add(startbutton);
            menu.Add(hashtext);
            menu.Add(errortext);
            menu.Add(pageToggle);
            foreach (var page in pages)
            {
                foreach (var item in page)
                {
                    menu.Add(item);
                }
            }

            Scene.Add(menu);
            syncModel();

            menu.OnCancel = () => {
                if (this.Entering || this.BuilderThread != null)
                {
                    return;
                }

                // save settings
                RandoModule.Instance.SavedData.SavedSettings = Settings.Copy();
                RandoModule.Instance.SaveSettings();

                Audio.Play(SFX.ui_main_button_back);
                Overworld.Goto <OuiMainMenu>();
            };

            menu.OnPause = () => {
                if (this.Entering || this.BuilderThread != null)
                {
                    return;
                }

                Audio.Play(SFX.ui_main_button_select);
                menu.Selection = 1;
                menu.Current.OnPressed();
            };

            menu.Selection = 1;
            return(menu);
        }