public void CreateEnabledEntry(TextMenu menu, bool inGame) { TextMenu.OnOff button = new TextMenu.OnOff(DialogIds.Enabled.DialogClean(), Enabled) { OnValueChange = value => { Enabled = value; bool mineItem = false; int mineItemsCount = 2; foreach (TextMenu.Item item in menu.Items) { if (item == menu.Current && !mineItem) { mineItem = true; continue; } if (!mineItem || mineItemsCount <= 0) { continue; } mineItemsCount--; item.Visible = value; } } }; menu.Add(button); }
public static void CreateMenu(EverestModule everestModule, TextMenu menu, bool inGame) { TextMenu.Item enabledItem = new TextMenu.OnOff("Enabled".ToDialogText(), Settings.Enabled).Change((value) => { Settings.Enabled = value; foreach (TextMenu.Item item in options) { item.Visible = value; } }); menu.Add(enabledItem); CreateOptions(everestModule, menu, inGame); foreach (TextMenu.Item item in options) { menu.Add(item); item.Visible = Settings.Enabled; } foreach (string text in Split(InputController.TasFilePath, 60).Reverse()) { enabledItem.AddDescription(menu, text); } enabledItem.AddDescription(menu, "Working TAS File Path:"); HitboxTweak.AddSubMenuDescription(menu, inGame); InfoHud.AddSubMenuDescription(menu); keyConfigButton.AddDescription(menu, "Key Config Description".ToDialogText()); }
public void CreateLogToIngameConsoleEntry(TextMenu textMenu, bool inGame) { TextMenu.Item item = new TextMenu.OnOff("Log to ingame console [DEBUG]", LogToIngameConsole) .Change(value => { LogToIngameConsole = value; }); textMenu.Add(item); }
public void CreateBackupAsZipFileEntry(TextMenu textMenu, bool inGame) { TextMenu.Item item = new TextMenu.OnOff(DialogId.Options.BackupAsZipFile.DialogClean(), BackupAsZipFile) .Change(value => { BackupAsZipFile = value; }); textMenu.Add(item); menuItems.Add(DialogId.Options.BackupAsZipFile, item); }
public void CreateAutoDeleteOldBackupsEntry(TextMenu textMenu, bool inGame) { TextMenu.Item item = new TextMenu.OnOff(DialogId.Options.AutoDeleteOldBackups.DialogClean(), AutoDeleteOldBackups) .Change(value => { AutoDeleteOldBackups = value; RefreshItemsStates(); }); textMenu.Add(item); menuItems.Add(DialogId.Options.AutoDeleteOldBackups, item); }
public static void CreateMenu(EverestModule everestModule, TextMenu menu, bool inGame) { List <TextMenuExt.EaseInSubHeaderExt> enabledDescriptions = new(); TextMenuExt.EaseInSubHeaderExt AddEnabledDescription(TextMenu.Item enabledItem, TextMenu containingMenu, string description) { TextMenuExt.EaseInSubHeaderExt descriptionText = new(description, false, containingMenu) { TextColor = Color.Gray, HeightExtra = 0f }; List <TextMenu.Item> items = containingMenu.GetItems(); if (items.Contains(enabledItem)) { containingMenu.Insert(items.IndexOf(enabledItem) + 1, descriptionText); } enabledItem.OnEnter += () => descriptionText.FadeVisible = Settings.Enabled; enabledItem.OnLeave += () => descriptionText.FadeVisible = false; return(descriptionText); } TextMenu.Item enabledItem = new TextMenu.OnOff("Enabled".ToDialogText(), Settings.Enabled).Change((value) => { Settings.Enabled = value; foreach (EaseInSubMenu easeInSubMenu in options) { easeInSubMenu.FadeVisible = value; } foreach (TextMenuExt.EaseInSubHeaderExt easeInSubHeader in enabledDescriptions) { easeInSubHeader.FadeVisible = value; } }); menu.Add(enabledItem); CreateOptions(everestModule, menu, inGame); foreach (EaseInSubMenu easeInSubMenu in options) { menu.Add(easeInSubMenu); } foreach (string text in Split(InputController.TasFilePath, 60).Reverse()) { enabledDescriptions.Add(AddEnabledDescription(enabledItem, menu, text)); } enabledDescriptions.Add(AddEnabledDescription(enabledItem, menu, "Enabled Description".ToDialogText())); HitboxMenu.AddSubMenuDescription(menu, inGame); InfoHud.AddSubMenuDescription(menu); hotkeysSubMenu.AddDescription(menu, "Hotkeys Description".ToDialogText()); }
public void CreateConnectionEntry(TextMenu menu, bool inGame) { if (Celeste.PlayMode == Celeste.PlayModes.Debug) { menu.Add(new TextMenu.SubHeader("modoptions_ghostnetmodule_debugwarn".DialogCleanOrNull() ?? "WARNING: DEBUG MODE DETECTED!")); } menu.Add( (EnabledEntry = new TextMenu.OnOff("modoptions_ghostnetmodule_connected".DialogCleanOrNull() ?? "Connected", Connection)) .Change(v => Connection = v) ); }
public void CreateEnabledEntry(TextMenu textMenu, bool inGame) { TextMenu.Item item = new TextMenu.OnOff(DialogId.Options.Enabled.DialogClean(), Enabled) .Change(value => { Enabled = value; if (Enabled) { InfiniteBackupsModule.Instance.Load(); } else { InfiniteBackupsModule.Instance.Unload(); } RefreshItemsStates(); }); textMenu.Add(item); menuItems.Add(DialogId.Options.Enabled, item); }
public void CreateMasterSwitchEntry(TextMenu menu, bool inGame) { if (inGame) { return; } var toggle = new TextMenu.OnOff(Dialog.Clean("modoptions_bingoclient_masterswitch"), this.MasterSwitch); toggle.OnValueChange = v => { this.MasterSwitch = v; if (v) { BingoClient.Instance.HookStuff(); } else { BingoClient.Instance.UnhookStuff(); } }; menu.Add(toggle); }
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); }
/// <summary> /// Create the mod menu subsection including the section header in the given menu. /// The default implementation uses reflection to attempt creating a menu. /// </summary> /// <param name="menu">Menu to add the section to.</param> /// <param name="inGame">Whether we're in-game (paused) or in the main menu.</param> /// <param name="snapshot">The Level.PauseSnapshot</param> public virtual void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot) { Type type = SettingsType; EverestModuleSettings settings = _Settings; if (type == null || settings == null) { return; } // The default name prefix. string typeName = type.Name.ToLowerInvariant(); if (typeName.EndsWith("settings")) { typeName = typeName.Substring(0, typeName.Length - 8); } string nameDefaultPrefix = $"modoptions_{typeName}_"; // Any attributes we may want to get and read from later. SettingInGameAttribute attribInGame; SettingRangeAttribute attribRange; // If the settings type has got the InGame attrib, only show it in the matching situation. if ((attribInGame = type.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { return; } // The settings subheader. string name; // We lazily reuse this field for the props later on. name = type.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}title"; name = name.DialogCleanOrNull() ?? Metadata.Name.SpacedPascalCase(); menu.Add(new TextMenu.SubHeader(name + " | v." + Metadata.VersionString)); PropertyInfo[] props; if (type == _PrevSettingsType) { props = _PrevSettingsProps; } else { _PrevSettingsProps = props = type.GetProperties(); _PrevSettingsType = type; } foreach (PropertyInfo prop in props) { MethodInfo creator = type.GetMethod( $"Create{prop.Name}Entry", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(TextMenu), typeof(bool) }, new ParameterModifier[0] ); if (creator != null) { creator.GetFastDelegate()(settings, menu, inGame); continue; } if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } name = prop.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}"; name = name.DialogCleanOrNull() ?? prop.Name.SpacedPascalCase(); bool needsRelaunch = prop.GetCustomAttribute <SettingNeedsRelaunchAttribute>() != null; TextMenu.Item item = null; Type propType = prop.PropertyType; object value = prop.GetValue(settings); // Create the matching item based off of the type and attributes. if (propType == typeof(bool)) { item = new TextMenu.OnOff(name, (bool)value) .Change(v => prop.SetValue(settings, v)) ; } else if ( propType == typeof(int) && (attribRange = prop.GetCustomAttribute <SettingRangeAttribute>()) != null ) { item = new TextMenu.Slider(name, i => i.ToString(), attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else if (propType.IsEnum) { Array enumValues = Enum.GetValues(propType); Array.Sort((int[])enumValues); string enumNamePrefix = $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}_"; item = new TextMenu.Slider(name, (i) => { string enumName = enumValues.GetValue(i).ToString(); string fullName = $"{enumNamePrefix}{enumName.ToLowerInvariant()}"; return(fullName.DialogCleanOrNull() ?? enumName); }, 0, enumValues.Length - 1, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else if (!inGame && propType == typeof(string)) { item = new TextMenu.Button(name + ": " + value) .Pressed(() => { Audio.Play(Sfxs.ui_main_savefile_rename_start); menu.SceneAs <Overworld>().Goto <OuiModOptionString>().Init <OuiModOptions>( (string)value, v => prop.SetValue(settings, v) ); }) ; } if (item == null) { continue; } if (needsRelaunch) { item = item.NeedsRelaunch(); } menu.Add(item); } }
private void ReloadMenu() { menu = new TextMenu { new TextMenu.Header(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_HEADER")), new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_TOGGLEALL")).Pressed(() => { var items = menu.GetItems(); TextMenu.OnOff firstToggle = null; foreach (var item in items) { if (item is TextMenu.OnOff) { firstToggle = item as TextMenu.OnOff; break; } } if (firstToggle == null) { // ??? return; } var newValue = 1 - firstToggle.Index; for (int i = 0; i < items.Count; i++) { if (items[i] is TextMenu.OnOff toggle) { toggle.Index = newValue; toggle.OnValueChange(toggle.Values[newValue].Item2); } } }), }; var lvlCount = new Dictionary <RandoSettings.AreaKeyNotStupid, int>(); foreach (var room in RandoLogic.AllRooms) { var notstupid = new RandoSettings.AreaKeyNotStupid(room.Area); if (lvlCount.TryGetValue(notstupid, out int c)) { lvlCount[notstupid] = c + 1; } else { lvlCount[notstupid] = 1; } } string currentSet = null; foreach (var key in RandoLogic.AvailableAreas) { var area = AreaData.Get(key); var mode = AreaData.GetMode(key); if (currentSet != area.GetLevelSet()) { currentSet = area.GetLevelSet(); menu.Add(new TextMenu.SubHeader(DialogExt.CleanLevelSet(currentSet))); } var on = Settings.MapIncluded(key); var name = area.Name; name = name.DialogCleanOrNull() ?? name.SpacedPascalCase(); if (key.Mode != AreaMode.Normal || (area.Mode.Length != 1 && area.Mode[1] != null)) { name += " " + Char.ToString((char)('A' + (int)key.Mode)); } menu.Add(new TextMenu.OnOff(name, on).Change(this.MakeChangeFunc(key))); menu.Add(new TextMenuExt.SubHeaderExt(lvlCount[new RandoSettings.AreaKeyNotStupid(key)].ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS")) { HeightExtra = -10f, Offset = new Vector2(30, -5), }); } if (currentSet != "Celeste") { menu.Insert(2, new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_RESET")).Pressed(() => { Settings.SetNormalMaps(); // this is a stupid way to do this int levelsetIdx = -1; foreach (var item in menu.GetItems()) { if (item is TextMenu.SubHeader && !(item is TextMenuExt.SubHeaderExt)) { levelsetIdx++; } else if (item is TextMenu.OnOff toggle) { toggle.Index = levelsetIdx == 0 ? 1 : 0; } } })); } Scene.Add(menu); }
protected override void addOptionsToMenu(TextMenu menu, bool inGame, object[] parameters) { OptionItems items = new OptionItems(); // Add the general settings menu.Add(new TextMenu.SubHeader(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_GENERALSETTINGS"))); menu.Add(new TextMenu.Slider(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_CHANGEVARIANTSINTERVAL"), i => { if (i == 0) { return(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_ONSCREENTRANSITION")); } return($"{Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_EVERY")} {changeVariantsIntervalScale[i]}s"); }, 0, changeVariantsIntervalScale.Length - 1, indexFromChangeVariantsInterval(ExtendedVariantsModule.Settings.ChangeVariantsInterval)) .Change(i => { ExtendedVariantsModule.Settings.ChangeVariantsInterval = changeVariantsIntervalScale[i]; refreshOptionMenuEnabledStatus(items); ExtendedVariantsModule.Instance.Randomizer.UpdateCountersFromSettings(); })); menu.Add(new TextMenu.Slider(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_VARIANTSET"), i => Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_" + new string[] { "OFF", "VANILLA", "EXTENDED", "BOTH" }[i]), 1, 3, ExtendedVariantsModule.Settings.VariantSet) .Change(i => { ExtendedVariantsModule.Settings.VariantSet = i; refreshOptionMenuEnabledStatus(items); })); TextMenu.Option <int> maxEnabledVariants = new TextMenu.Slider( Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_MAXENABLEDVARIANTS" + (ExtendedVariantsModule.Settings.RerollMode ? "_REROLL" : "")), i => i.ToString(), 0, ExtendedVariantsModule.Instance.VariantHandlers.Count + 13, ExtendedVariantsModule.Settings.MaxEnabledVariants) .Change(newValue => ExtendedVariantsModule.Settings.MaxEnabledVariants = newValue); menu.Add(new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_REROLLMODE"), ExtendedVariantsModule.Settings.RerollMode) .Change(newValue => { ExtendedVariantsModule.Settings.RerollMode = newValue; maxEnabledVariants.Label = Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_MAXENABLEDVARIANTS" + (newValue ? "_REROLL" : "")); })); menu.Add(maxEnabledVariants); menu.Add(items.VanillafyOption = new TextMenu.Slider(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_VANILLAFY"), i => { if (i == 0) { return(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_DISABLED")); } i = vanillafyScale[i]; if (i < 60) { return($"{i.ToString()}s"); } return($"{(i / 60).ToString()} min"); }, 0, vanillafyScale.Length - 1, indexFromVanillafyScale(ExtendedVariantsModule.Settings.Vanillafy)) .Change(newValue => { ExtendedVariantsModule.Settings.Vanillafy = vanillafyScale[newValue]; ExtendedVariantsModule.Instance.Randomizer.UpdateCountersFromSettings(); })); menu.Add(new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_DISPLAYONSCREEN"), ExtendedVariantsModule.Settings.DisplayEnabledVariantsToScreen) .Change(newValue => ExtendedVariantsModule.Settings.DisplayEnabledVariantsToScreen = newValue)); if (!inGame) { TextMenu.Button seedButton = new TextMenu.Button(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_SEEDINPUT") + " " + ExtendedVariantsModule.Settings.RandoSetSeed); seedButton.Pressed(() => { returnIndex = menu.Selection; Audio.Play(SFX.ui_main_savefile_rename_start); menu.SceneAs <Overworld>().Goto <OuiModOptionString>().Init <OuiRandomizerOptions>( ExtendedVariantsModule.Settings.RandoSetSeed, v => ExtendedVariantsModule.Settings.RandoSetSeed = v, 25 ); }); TextMenu.Option <bool> toggle = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_SETSEED"), ExtendedVariantsModule.Settings.RandoSetSeed != null) .Change(newValue => { ExtendedVariantsModule.Settings.RandoSetSeed = (newValue ? "seed" : null); seedButton.Visible = newValue; seedButton.Label = Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_SEEDINPUT") + " seed"; }); seedButton.Visible = ExtendedVariantsModule.Settings.RandoSetSeed != null; menu.Add(toggle); toggle.AddDescription(menu, Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_SEEDDESCRIPTION2")); toggle.AddDescription(menu, Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_SEEDDESCRIPTION1")); menu.Add(seedButton); } // build the toggles to individually enable or disable all vanilla variants menu.Add(new TextMenu.SubHeader(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_ENABLED_VANILLA"))); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.GameSpeed)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.MirrorMode)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.ThreeSixtyDashing)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.InvisibleMotion)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.NoGrabbing)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.LowFriction)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.SuperDashing)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.Hiccups)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.PlayAsBadeline)); menu.Add(new TextMenu.SubHeader(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_ENABLED_VANILLA_ASSISTS"))); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.InfiniteStamina)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.DashMode)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.Invincible)); items.VanillaVariantOptions.Add(addToggleOptionToMenu(menu, VanillaVariant.DashAssist)); // and do the same with extended ones menu.Add(new TextMenu.SubHeader(Dialog.Clean("MODOPTIONS_EXTENDEDVARIANTS_RANDOMIZER_ENABLED_EXTENDED"))); foreach (ExtendedVariantsModule.Variant variant in ExtendedVariantsModule.Instance.VariantHandlers.Keys) { items.ExtendedVariantOptions.Add(addToggleOptionToMenu(menu, variant)); } refreshOptionMenuEnabledStatus(items); if (returnIndex >= 0) { menu.Selection = returnIndex; returnIndex = -1; } }
private Tuple <List <TextMenu.Item>, Action> MakeMapPicker(Action syncOutward) { var menu = new List <TextMenu.Item>(); var toggleAll = new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_TOGGLEALL")).Pressed(() => { TextMenu.OnOff firstToggle = null; foreach (var item in menu) { if (item is TextMenu.OnOff) { firstToggle = item as TextMenu.OnOff; break; } } if (firstToggle == null) { // ??? return; } var newValue = 1 - firstToggle.Index; foreach (var item in menu) { if (item is TextMenu.OnOff toggle) { toggle.Index = newValue; toggle.OnValueChange(toggle.Values[newValue].Item2); } } }); menu.Add(toggleAll); var mapcountlbl = new TextMenuExt.SubHeaderExt(Settings.LevelCount.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS")) { HeightExtra = -10f, Offset = new Vector2(30, -5), }; menu.Add(mapcountlbl); void syncTotal() { mapcountlbl.Title = Settings.LevelCount.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS"); } void syncInner() { syncOutward(); syncTotal(); } Action AddAreaToggle(string name, AreaKey key) { var toggle = new TextMenu.OnOff(name, false); Action syncFunc = () => { var on = Settings.MapIncluded(key); toggle.Index = on ? 1 : 0; }; var numLevels = RandoLogic.LevelCount[new RandoSettings.AreaKeyNotStupid(key)]; menu.Add(toggle.Change(this.MakeChangeFunc(key, syncInner))); menu.Add(new TextMenuExt.SubHeaderExt(numLevels.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS")) { HeightExtra = -10f, Offset = new Vector2(30, -5), }); syncFunc(); return(syncFunc); } Action AddLevelSetToggle(string name, List <AreaKey> keys) { var toggle = new TextMenu.OnOff(name, false); Action syncFunc = () => { var on = Settings.MapIncluded(keys[0]); toggle.Index = on ? 1 : 0; }; var numLevels = 0; foreach (AreaKey key in keys) { numLevels += RandoLogic.LevelCount[new RandoSettings.AreaKeyNotStupid(key)]; } menu.Add(toggle.Change(this.MakeChangeFunc(keys, syncInner))); menu.Add(new TextMenuExt.SubHeaderExt(numLevels.ToString() + " " + Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_LEVELS")) { HeightExtra = -10f, Offset = new Vector2(30, -5), }); syncFunc(); return(syncFunc); } Action AddLevelSetMenu(string levelSetID) { List <AreaKey> keys = RandoLogic.LevelSets[levelSetID]; var syncFuncs = new List <Action>(); menu.Add(new TextMenu.SubHeader(DialogExt.CleanLevelSet(keys[0].GetLevelSet()))); foreach (var key in keys) { var area = AreaData.Get(key); var name = area.Name; name = name.DialogCleanOrNull() ?? name.SpacedPascalCase(); if (key.Mode != AreaMode.Normal || (area.Mode.Length != 1 && area.Mode[1] != null)) { name += " " + Char.ToString((char)('A' + (int)key.Mode)); } syncFuncs.Add(AddAreaToggle(name, key)); } return(() => { foreach (var a in syncFuncs) { a(); } syncTotal(); }); } var allSyncs = new List <Action>(); // Create submenu for Celeste, campaigns, then other levelsets allSyncs.Add(AddLevelSetMenu("Celeste")); List <string> completedLevelSets = new List <string> { "Celeste" }; var campaigns = RandoModule.Instance.MetaConfig.Campaigns; foreach (RandoMetadataCampaign campaign in campaigns) { menu.Add(new TextMenu.SubHeader(DialogExt.CleanLevelSet(campaign.Name))); foreach (RandoMetadataLevelSet levelSet in campaign.LevelSets) { var name = levelSet.Name; if (RandoLogic.LevelSets.TryGetValue(levelSet.ID, out var keys)) { allSyncs.Add(AddLevelSetToggle(name, keys)); completedLevelSets.Add(levelSet.ID); } } } foreach (string levelSet in RandoLogic.LevelSets.Keys) { if (!completedLevelSets.Contains(levelSet)) { allSyncs.Add(AddLevelSetMenu(levelSet)); } } // If Celeste is not the only levelset, Reset should turn all other levelsets off if (RandoLogic.LevelSets.Count > 1) { menu.Insert(2, new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_RESET")).Pressed(() => { Settings.SetNormalMaps(); // this is a stupid way to do this int levelsetIdx = -1; foreach (var item in menu) { if (item is TextMenu.SubHeader && !(item is TextMenuExt.SubHeaderExt)) { levelsetIdx++; } else if (item is TextMenu.OnOff toggle) { toggle.Index = levelsetIdx == 0 ? 1 : 0; } } })); } Action finalSync = () => { foreach (var aa in allSyncs) { aa(); } }; return(Tuple.Create(menu, finalSync)); }
/// <summary> /// Create the mod menu subsection including the section header in the given menu. /// The default implementation uses reflection to attempt creating a menu. /// </summary> /// <param name="menu">Menu to add the section to.</param> /// <param name="inGame">Whether we're in-game (paused) or in the main menu.</param> /// <param name="snapshot">The Level.PauseSnapshot</param> public virtual void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot) { Type type = SettingsType; EverestModuleSettings settings = _Settings; if (type == null || settings == null) { return; } // The default name prefix. string nameDefaultPrefix = $"modoptions_{type.Name.ToLowerInvariant()}_"; if (nameDefaultPrefix.EndsWith("Settings")) { nameDefaultPrefix = nameDefaultPrefix.Substring(0, nameDefaultPrefix.Length - 8); } // Any attributes we may want to get and read from later. SettingInGameAttribute attribInGame; SettingRangeAttribute attribRange; // If the settings type has got the InGame attrib, only show it in the matching situation. if ((attribInGame = type.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { return; } // The settings subheader. string name; // We lazily reuse this field for the props later on. name = type.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}title"; name = name.DialogCleanOrNull() ?? Metadata.Name.SpacedPascalCase(); menu.Add(new TextMenu.SubHeader(name)); PropertyInfo[] props; if (type == _PrevSettingsType) { props = _PrevSettingsProps; } else { _PrevSettingsProps = props = type.GetProperties(); _PrevSettingsType = type; } foreach (PropertyInfo prop in props) { if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } name = prop.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}"; name = name.DialogCleanOrNull() ?? prop.Name.SpacedPascalCase(); bool needsRelaunch = prop.GetCustomAttribute <SettingNeedsRelaunchAttribute>() != null; TextMenu.Item item = null; Type propType = prop.PropertyType; object value = prop.GetValue(settings); // Create the matching item based off of the type and attributes. if (propType == typeof(bool)) { item = new TextMenu.OnOff(name, (bool)value) .Change(v => prop.SetValue(settings, v)) .NeedsRelaunch(needsRelaunch) ; } else if ( propType == typeof(int) && (attribRange = prop.GetCustomAttribute <SettingRangeAttribute>()) != null ) { item = new TextMenu.Slider(name, i => i.ToString(), attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) .NeedsRelaunch(needsRelaunch) ; } if (item == null) { continue; } menu.Add(item); } }
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); }
protected override void addOptionsToMenu(TextMenu menu) { // for now, display a "loading" message. TextMenu.Button loading = new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_LOADING")) { Disabled = true }; menu.Add(loading); modLoadingTask = new Task(() => { // load all the mod yamls (that can take some time), update the progress every 500ms so that the text doesn't go crazy since it is centered. Stopwatch updateTimer = Stopwatch.StartNew(); modYamls = LoadAllModYamls(progress => { if (updateTimer.ElapsedMilliseconds > 500) { updateTimer.Restart(); loading.Label = $"{Dialog.Clean("MODOPTIONS_MODTOGGLE_LOADING")} ({(int) (progress * 100)}%)"; } }); updateTimer.Stop(); MainThreadHelper.Do(() => { modToggles = new Dictionary <string, TextMenu.OnOff>(); // remove the "loading..." message menu.Remove(loading); // if there is a whitelist, warn the user that it will break those settings. if (Everest.Loader.Whitelist != null) { menu.Add(restartMessage1 = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_WHITELISTWARN")) { TextColor = Color.OrangeRed }); } // display the warning about blacklist.txt + restarting menu.Add(restartMessage1 = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_MESSAGE_1"))); menu.Add(restartMessage2 = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_MESSAGE_2")) { HeightExtra = 0f }); menu.Add(new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MODTOGGLE_MESSAGE_3")) { HeightExtra = 20f, TextColor = Color.Goldenrod }); // reduce spacing between the whitelist warning and the blacklist overwrite warning if (Everest.Loader.Whitelist != null) { restartMessage1.HeightExtra = 30f; } // "enable all" and "disable all" buttons menu.Add(new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_ENABLEALL")).Pressed(() => { foreach (TextMenu.OnOff toggle in modToggles.Values) { toggle.Index = 1; } blacklistedMods.Clear(); updateHighlightedMods(); })); menu.Add(new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_DISABLEALL")).Pressed(() => { blacklistedMods.Clear(); foreach (KeyValuePair <string, TextMenu.OnOff> toggle in modToggles) { toggle.Value.Index = 0; blacklistedMods.Add(toggle.Key); } updateHighlightedMods(); })); // "toggle dependencies automatically" button TextMenu.Item toggleDependenciesButton; menu.Add(toggleDependenciesButton = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEDEPS"), true) .Change(value => toggleDependencies = value)); toggleDependenciesButton.AddDescription(menu, Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEDEPS_MESSAGE2")); toggleDependenciesButton.AddDescription(menu, Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEDEPS_MESSAGE1")); // "cancel" button to leave the screen without saving menu.Add(new TextMenu.Button(Dialog.Clean("MODOPTIONS_MODTOGGLE_CANCEL")).Pressed(() => { blacklistedMods = blacklistedModsOriginal; onBackPressed(Overworld); })); // reset the mods list allMods = new List <string>(); blacklistedMods = new HashSet <string>(); string[] files; bool headerInserted; // crawl directories files = Directory.GetDirectories(Everest.Loader.PathMods); Array.Sort(files, (a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant())); headerInserted = false; for (int i = 0; i < files.Length; i++) { string file = Path.GetFileName(files[i]); if (file != "Cache") { if (!headerInserted) { menu.Add(new patch_TextMenu.patch_SubHeader(Dialog.Clean("MODOPTIONS_MODTOGGLE_DIRECTORIES"))); headerInserted = true; } addFileToMenu(menu, file); } } // crawl zips files = Directory.GetFiles(Everest.Loader.PathMods); Array.Sort(files, (a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant())); headerInserted = false; for (int i = 0; i < files.Length; i++) { string file = Path.GetFileName(files[i]); if (file.EndsWith(".zip")) { if (!headerInserted) { menu.Add(new patch_TextMenu.patch_SubHeader(Dialog.Clean("MODOPTIONS_MODTOGGLE_ZIPS"))); headerInserted = true; } addFileToMenu(menu, file); } } // crawl map bins files = Directory.GetFiles(Everest.Loader.PathMods); Array.Sort(files, (a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant())); headerInserted = false; for (int i = 0; i < files.Length; i++) { string file = Path.GetFileName(files[i]); if (file.EndsWith(".bin")) { if (!headerInserted) { menu.Add(new patch_TextMenu.patch_SubHeader(Dialog.Clean("MODOPTIONS_MODTOGGLE_BINS"))); headerInserted = true; } addFileToMenu(menu, file); } } // sort the mods list alphabetically, for output in the blacklist.txt file later. allMods.Sort((a, b) => a.ToLowerInvariant().CompareTo(b.ToLowerInvariant())); // adjust the mods' color if they are required dependencies for other mods foreach (KeyValuePair <string, TextMenu.OnOff> toggle in modToggles) { if (modHasDependencies(toggle.Key)) { ((patch_TextMenu.patch_Option <bool>)(object) toggle.Value).UnselectedColor = Color.Goldenrod; } } // snap the menu so that it doesn't show a scroll up. menu.Y = menu.ScrollTargetY; // clone the list to be able to check if the list changed when leaving the menu. blacklistedModsOriginal = new HashSet <string>(blacklistedMods); // loading is done! modLoadingTask = null; }); }); modLoadingTask.Start(); }
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); }
/// <summary> /// Create the mod menu subsection including the section header in the given menu. /// The default implementation uses reflection to attempt creating a menu. /// </summary> /// <param name="menu">Menu to add the section to.</param> /// <param name="inGame">Whether we're in-game (paused) or in the main menu.</param> /// <param name="snapshot">The Level.PauseSnapshot</param> public virtual void CreateModMenuSection(TextMenu menu, bool inGame, EventInstance snapshot) { Type type = SettingsType; EverestModuleSettings settings = _Settings; if (type == null || settings == null) { return; } // The default name prefix. string typeName = type.Name.ToLowerInvariant(); if (typeName.EndsWith("settings")) { typeName = typeName.Substring(0, typeName.Length - 8); } string nameDefaultPrefix = $"modoptions_{typeName}_"; // Any attributes we may want to get and read from later. SettingInGameAttribute attribInGame; SettingRangeAttribute attribRange; SettingNumberInputAttribute attribNumber; // If the settings type has got the InGame attrib, only show it in the matching situation. if ((attribInGame = type.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { return; } bool headerCreated = false; if (GetType().GetMethod("CreateModMenuSection").DeclaringType != typeof(EverestModule)) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } PropertyInfo[] props; if (type == _PrevSettingsType) { props = _PrevSettingsProps; } else { _PrevSettingsProps = props = type.GetProperties(); _PrevSettingsType = type; } foreach (PropertyInfo prop in props) { MethodInfo creator = type.GetMethod( $"Create{prop.Name}Entry", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(TextMenu), typeof(bool) }, new ParameterModifier[0] ); if (creator != null) { if (!headerCreated) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } creator.GetFastDelegate()(settings, menu, inGame); continue; } if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } string name = prop.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}"; name = name.DialogCleanOrNull() ?? prop.Name.SpacedPascalCase(); bool needsRelaunch = prop.GetCustomAttribute <SettingNeedsRelaunchAttribute>() != null; string description = prop.GetCustomAttribute <SettingSubTextAttribute>()?.Description; TextMenu.Item item = null; Type propType = prop.PropertyType; object value = prop.GetValue(settings); // Create the matching item based off of the type and attributes. if (propType == typeof(bool)) { item = new TextMenu.OnOff(name, (bool)value) .Change(v => prop.SetValue(settings, v)) ; } else if ( propType == typeof(int) && (attribRange = prop.GetCustomAttribute <SettingRangeAttribute>()) != null ) { if (attribRange.LargeRange) { item = new TextMenuExt.IntSlider(name, attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else { item = new TextMenu.Slider(name, i => i.ToString(), attribRange.Min, attribRange.Max, (int)value) .Change(v => prop.SetValue(settings, v)) ; } } else if ((propType == typeof(int) || propType == typeof(float)) && (attribNumber = prop.GetCustomAttribute <SettingNumberInputAttribute>()) != null) { float currentValue; Action <float> valueSetter; if (propType == typeof(int)) { currentValue = (int)value; valueSetter = v => prop.SetValue(settings, (int)v); } else { currentValue = (float)value; valueSetter = v => prop.SetValue(settings, v); } int maxLength = attribNumber.MaxLength; bool allowNegatives = attribNumber.AllowNegatives; item = new TextMenu.Button(name + ": " + currentValue.ToString($"F{maxLength}").TrimEnd('0').TrimEnd('.')) .Pressed(() => { Audio.Play(SFX.ui_main_savefile_rename_start); menu.SceneAs <Overworld>().Goto <OuiNumberEntry>().Init <OuiModOptions>( currentValue, valueSetter, maxLength, propType == typeof(float), allowNegatives ); }) ; } else if (propType.IsEnum) { Array enumValues = Enum.GetValues(propType); Array.Sort((int[])enumValues); string enumNamePrefix = $"{nameDefaultPrefix}{prop.Name.ToLowerInvariant()}_"; item = new TextMenu.Slider(name, (i) => { string enumName = enumValues.GetValue(i).ToString(); return ($"{enumNamePrefix}{enumName.ToLowerInvariant()}".DialogCleanOrNull() ?? $"modoptions_{propType.Name.ToLowerInvariant()}_{enumName.ToLowerInvariant()}".DialogCleanOrNull() ?? enumName); }, 0, enumValues.Length - 1, (int)value) .Change(v => prop.SetValue(settings, v)) ; } else if (!inGame && propType == typeof(string)) { int maxValueLength = prop.GetCustomAttribute <SettingMaxLengthAttribute>()?.Max ?? 12; int minValueLength = prop.GetCustomAttribute <SettingMinLengthAttribute>()?.Min ?? 1; item = new TextMenu.Button(name + ": " + value) .Pressed(() => { Audio.Play(SFX.ui_main_savefile_rename_start); menu.SceneAs <Overworld>().Goto <OuiModOptionString>().Init <OuiModOptions>( (string)value, v => prop.SetValue(settings, v), maxValueLength, minValueLength ); }) ; } if (item == null) { continue; } if (!headerCreated) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } menu.Add(item); if (needsRelaunch) { item = item.NeedsRelaunch(menu); } if (description != null) { item = item.AddDescription(menu, description.DialogCleanOrNull() ?? description); } } foreach (PropertyInfo prop in type.GetProperties()) { if ((attribInGame = prop.GetCustomAttribute <SettingInGameAttribute>()) != null && attribInGame.InGame != inGame) { continue; } if (prop.GetCustomAttribute <SettingIgnoreAttribute>() != null) { continue; } if (!prop.CanRead || !prop.CanWrite) { continue; } if (!typeof(ButtonBinding).IsAssignableFrom(prop.PropertyType)) { continue; } if (!headerCreated) { CreateModMenuSectionHeader(menu, inGame, snapshot); headerCreated = true; } CreateModMenuSectionKeyBindings(menu, inGame, snapshot); break; } }
private void ReloadMenu() { menu = new TextMenu { new TextMenu.Header(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_HEADER")), new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_TOGGLEALL")).Pressed(() => { var items = menu.GetItems(); TextMenu.OnOff firstToggle = null; foreach (var item in items) { if (item is TextMenu.OnOff) { firstToggle = item as TextMenu.OnOff; break; } } if (firstToggle == null) { // ??? return; } var newValue = 1 - firstToggle.Index; for (int i = 0; i < items.Count; i++) { if (items[i] is TextMenu.OnOff toggle) { toggle.Index = newValue; toggle.OnValueChange(toggle.Values[newValue].Item2); } } }), }; // Create submenu for Celeste, campaigns, then other levelsets AddLevelSetMenu("Celeste"); List <string> completedLevelSets = new List <string> { "Celeste" }; var campaigns = RandoModule.Instance.MetaConfig.Campaigns; foreach (RandoMetadataCampaign campaign in campaigns) { menu.Add(new TextMenu.SubHeader(DialogExt.CleanLevelSet(campaign.Name))); foreach (RandoMetadataLevelSet levelSet in campaign.LevelSets) { var name = levelSet.Name; if (RandoLogic.LevelSets.TryGetValue(levelSet.ID, out var keys)) { AddLevelSetToggle(name, keys); completedLevelSets.Add(levelSet.ID); } } } foreach (string levelSet in RandoLogic.LevelSets.Keys) { if (!completedLevelSets.Contains(levelSet)) { AddLevelSetMenu(levelSet); } } // If Celeste is not the only levelset, Reset should turn all other levelsets off if (RandoLogic.LevelSets.Count > 1) { menu.Insert(2, new TextMenu.Button(Dialog.Clean("MODOPTIONS_RANDOMIZER_MAPPICKER_RESET")).Pressed(() => { Settings.SetNormalMaps(); // this is a stupid way to do this int levelsetIdx = -1; foreach (var item in menu.GetItems()) { if (item is TextMenu.SubHeader && !(item is TextMenuExt.SubHeaderExt)) { levelsetIdx++; } else if (item is TextMenu.OnOff toggle) { toggle.Index = levelsetIdx == 0 ? 1 : 0; } } })); } Scene.Add(menu); }