diff --git a/.editorconfig b/.editorconfig index 3f0cacf93..0aa4b0726 100644 --- a/.editorconfig +++ b/.editorconfig @@ -269,6 +269,11 @@ dotnet_style_qualification_for_property = false:silent dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_event = false:silent +# Remove warning about invalid name like __instance +dotnet_diagnostic.IDE1006.severity = none +# Remove suggestion to reduce NULL checking +dotnet_diagnostic.IDE0031.severity = none + [*.{appxmanifest,asax,ascx,aspx,axaml,blockshader,build,c,c++,c++m,cc,ccm,cginc,compute,cp,cpp,cppm,cs,cshtml,cu,cuh,cxx,cxxm,dtd,fs,fsi,fsscript,fsx,fx,fxh,h,h++,hh,hlsl,hlsli,hlslinc,hp,hpp,hxx,icc,inc,inl,ino,ipp,ixx,master,ml,mli,mpp,mq4,mq5,mqh,mxx,nuspec,paml,razor,resw,resx,shader,shaderFoundry,skin,tcc,tpp,urtshader,usf,ush,uxml,vb,xaml,xamlx,xoml,xsd}] indent_style = space indent_size = 4 diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index e8562213f..1d5867872 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -3378,7 +3378,8 @@ public static class Options public static void SetupRoleOptions(int id, TabGroup tab, CustomRoles role, CustomGameMode customGameMode = CustomGameMode.Standard, bool zeroOne = false) { - var spawnOption = new StringOptionItem(id, role.ToString(), zeroOne ? RatesZeroOne : Rates, 0, tab).SetColor(Utils.GetRoleColor(role)) + var spawnOption = new StringOptionItem(id, role.ToString(), zeroOne ? RatesZeroOne : Rates, 0, tab) + .SetColor(Utils.GetRoleColor(role)) .SetHeader(true) .SetGameMode(customGameMode) as StringOptionItem; diff --git a/Modules/OptionItem/OptionItem.cs b/Modules/OptionItem/OptionItem.cs index 82445ac0f..4cbe174ee 100644 --- a/Modules/OptionItem/OptionItem.cs +++ b/Modules/OptionItem/OptionItem.cs @@ -1,6 +1,7 @@ +using EHR.Modules; +using EHR.Patches; using System; using System.Collections.Generic; -using EHR.Modules; using UnityEngine; namespace EHR; @@ -230,13 +231,13 @@ public abstract class OptionItem return IsSingleValue ? SingleValue : AllValues[CurrentPreset]; } - public bool IsCurrentlyHidden() + public bool IsCurrentlyHidden(bool forLobbyView = false, bool checkCollapsedSection = true) { try { for (OptionItem current = this; current != null; current = current.Parent) { - if (Hidden(current)) + if (Hidden(current, forLobbyView, checkCollapsedSection)) return true; } } @@ -244,10 +245,10 @@ public abstract class OptionItem return false; - static bool Hidden(OptionItem oi) + static bool Hidden(OptionItem oi, bool forLobbyView, bool checkCollapsedSection) { - if (oi.Header is { CollapsesSection: true }) return true; - CustomGameMode mode = EHR.Options.CurrentGameMode; + if (checkCollapsedSection && oi.Header is { CollapsesSection: true }) return true; + CustomGameMode mode = !forLobbyView ? EHR.Options.CurrentGameMode : LobbyViewSettingsPanePatch.LastGameModeSelected; const CustomGameMode nd = CustomGameMode.NaturalDisasters; return (oi.IsHidden || (oi.GameMode != CustomGameMode.All && oi.GameMode != mode) || (oi.Name == "IntegrateNaturalDisasters" && mode == nd)) && diff --git a/Modules/OptionShower.cs b/Modules/OptionShower.cs index e931ed32c..060bc5cbf 100644 --- a/Modules/OptionShower.cs +++ b/Modules/OptionShower.cs @@ -17,6 +17,7 @@ public static class OptionShower static OptionShower() { } + // Now EHR use LobbyViewSettingsPane instead of this public static string GetTextNoFresh() { try diff --git a/Modules/RPC.cs b/Modules/RPC.cs index aa5c1c61e..863884c1a 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -476,7 +476,7 @@ internal static class RPCHandlerPatch } OptionSaver.Save(); - Main.Instance.StartCoroutine(OptionShower.GetText()); + //Main.Instance.StartCoroutine(OptionShower.GetText()); break; } case CustomRPC.SetDeathReason: diff --git a/Modules/Translator.cs b/Modules/Translator.cs index 818619809..dd23ad419 100644 --- a/Modules/Translator.cs +++ b/Modules/Translator.cs @@ -1,4 +1,5 @@ -using System; +using EHR.Gamemodes; +using System; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -7,7 +8,6 @@ using System.Reflection; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; -using EHR.Gamemodes; namespace EHR; @@ -325,4 +325,14 @@ public static class Translator return OriginalRoleNames.TryGetValue(role, out var d) && d.TryGetValue(GetUserTrueLang(), out var o) ? infoLong.Replace(o, role.ToColoredString(), StringComparison.OrdinalIgnoreCase) : infoLong; } + public static bool LangHasSensitiveOutlineText() + { + return TranslationController.InstanceExists && TranslationController.Instance.currentLanguage.languageID is + SupportedLangs.Russian or + SupportedLangs.Korean or + SupportedLangs.Japanese or + SupportedLangs.SChinese or + SupportedLangs.TChinese; + } + } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index cf4d120e7..7203d55ba 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -464,6 +464,23 @@ public static class Utils _ = ColorUtility.TryParseHtmlString(hexColor, out Color c); return c; } + public static Color GetTabColor(this TabGroup tab) + { + return tab switch + { + TabGroup.SystemSettings => new(0.2f, 0.2f, 0.2f), + TabGroup.GameSettings => new(0.2f, 0.4f, 0.3f), + TabGroup.TaskSettings => new(0.4f, 0.2f, 0.5f), + TabGroup.ImpostorRoles => new(0.5f, 0.2f, 0.2f), + TabGroup.CrewmateRoles => new(0.2f, 0.4f, 0.5f), + TabGroup.NeutralRoles => new(0.5f, 0.4f, 0.2f), + TabGroup.CovenRoles => new(0.5f, 0.2f, 0.4f), + TabGroup.Addons => new(0.4f, 0.2f, 0.3f), + TabGroup.OtherRoles => new(0.4f, 0.4f, 0.4f), + TabGroup.PresetExplorer => new(0.5f, 0.5f, 0.5f), + _ => new(0.3f, 0.3f, 0.3f) + }; + } public static string GetRoleColorCode(CustomRoles role) { @@ -4410,7 +4427,7 @@ public static class Utils return null; } - + private static unsafe Texture2D LoadTextureFromResources(string path) { try diff --git a/Patches/ControlPatch.cs b/Patches/ControlPatch.cs index 489fefee1..c42bdbd3c 100644 --- a/Patches/ControlPatch.cs +++ b/Patches/ControlPatch.cs @@ -48,7 +48,7 @@ internal static class ControllerManagerUpdatePatch if (GameStates.IsLobby && (!HudManager.Instance.Chat || !HudManager.Instance.Chat.IsOpenOrOpening)) { - if (Input.GetKeyDown(KeyCode.Tab)) OptionShower.Next(); + //if (Input.GetKeyDown(KeyCode.Tab)) OptionShower.Next(); for (var i = 0; i < 9; i++) { diff --git a/Patches/GameOptionsMenuPatch.cs b/Patches/GameOptionsMenuPatch.cs index 39587b83e..f3acd8122 100644 --- a/Patches/GameOptionsMenuPatch.cs +++ b/Patches/GameOptionsMenuPatch.cs @@ -125,7 +125,8 @@ public static class GameOptionsMenuPatch OptionItem option = OptionItem.AllOptions[index]; if (option.Tab != modTab) continue; - bool enabled = !option.IsCurrentlyHidden() && AllParentsEnabledAndVisible(option.Parent); + bool enabledOrNotCollapsed = !option.IsCurrentlyHidden() && AllParentsEnabledAndVisible(option.Parent); + bool enabled = !option.IsCurrentlyHidden(checkCollapsedSection: false) && AllParentsEnabledAndVisible(option.Parent, checkCollapsedSection: false); if (option is TextOptionItem toi) { @@ -155,14 +156,14 @@ public static class GameOptionsMenuPatch categoryHeaderMasked.gameObject.SetActive(enabled); ModGameOptionsMenu.CategoryHeaderList.TryAdd(index, categoryHeaderMasked); - if (enabled) num -= 0.63f; + if (enabledOrNotCollapsed) num -= 0.63f; header = toi; continue; } option.Header = header; - if (option.IsHeader && enabled) + if (option.IsHeader && enabledOrNotCollapsed) num -= 0.18f; BaseGameSetting baseGameSetting = GetSetting(option); @@ -194,13 +195,13 @@ public static class GameOptionsMenuPatch optionBehaviour.SetUpFromData(baseGameSetting, 20); ModGameOptionsMenu.OptionList.TryAdd(optionBehaviour, index); ModGameOptionsMenu.BehaviourList.TryAdd(index, optionBehaviour); - optionBehaviour.gameObject.SetActive(enabled); + optionBehaviour.gameObject.SetActive(enabledOrNotCollapsed); optionBehaviour.OnValueChanged = new Action(__instance.ValueChanged); __instance.Children.Add(optionBehaviour); option.OptionBehaviour = optionBehaviour; - if (enabled) num -= 0.45f; + if (enabledOrNotCollapsed) num -= 0.45f; } catch (Exception e) { Utils.ThrowException(e); } @@ -221,11 +222,11 @@ public static class GameOptionsMenuPatch { if (option.Tab != modTab) continue; - bool enabled = !option.IsCurrentlyHidden() && AllParentsEnabledAndVisible(option.Parent); + bool enabledOrNotCollapsed = !option.IsCurrentlyHidden() && AllParentsEnabledAndVisible(option.Parent); if (option is TextOptionItem) num -= 0.63f; - else if (enabled) + else if (enabledOrNotCollapsed) { if (option.IsHeader) num -= 0.18f; @@ -237,12 +238,12 @@ public static class GameOptionsMenuPatch } } - private static bool AllParentsEnabledAndVisible(OptionItem o) + public static bool AllParentsEnabledAndVisible(OptionItem o, bool checkCollapsedSection = true) { while (true) { if (o == null) return true; - if (o.IsCurrentlyHidden() || !o.GetBool()) return false; + if (o.IsCurrentlyHidden(forLobbyView: false, checkCollapsedSection: checkCollapsedSection) || !o.GetBool()) return false; o = o.Parent; } } @@ -324,7 +325,15 @@ public static class GameOptionsMenuPatch } } } + [HarmonyPatch(nameof(GameOptionsMenu.Update))] + [HarmonyPrefix] + public static void UpdatePostfix(GameOptionsMenu __instance) + { + // Disable scroll options when chat open + if (!HudManager.InstanceExists || !__instance.gameObject.activeSelf) return; + __instance.scrollBar.enabled = !HudManager.Instance.Chat.IsOpenOrOpening; + } [HarmonyPatch(nameof(GameOptionsMenu.ValueChanged))] [HarmonyPrefix] private static bool ValueChangedPrefix(GameOptionsMenu __instance, OptionBehaviour option) @@ -353,21 +362,22 @@ public static class GameOptionsMenuPatch OptionItem option = OptionItem.AllOptions[index]; if (option.Tab != modTab) continue; - bool enabled = !option.IsCurrentlyHidden() && AllParentsEnabledAndVisible(option.Parent); + bool enabledOrNotCollapsed = !option.IsCurrentlyHidden() && AllParentsEnabledAndVisible(option.Parent); + bool enabled = !option.IsCurrentlyHidden(checkCollapsedSection: false) && AllParentsEnabledAndVisible(option.Parent, checkCollapsedSection: false); if (ModGameOptionsMenu.CategoryHeaderList.TryGetValue(index, out CategoryHeaderMasked categoryHeaderMasked)) { categoryHeaderMasked.transform.localPosition = new(-0.903f, num, -2f); categoryHeaderMasked.gameObject.SetActive(enabled); - if (enabled) num -= 0.63f; + if (enabledOrNotCollapsed) num -= 0.63f; } - else if (option.IsHeader && enabled) num -= 0.18f; + else if (option.IsHeader && enabledOrNotCollapsed) num -= 0.18f; if (ModGameOptionsMenu.BehaviourList.TryGetValue(index, out OptionBehaviour optionBehaviour)) { optionBehaviour.transform.localPosition = new(0.952f, num, -2f); - optionBehaviour.gameObject.SetActive(enabled); - if (enabled) num -= 0.45f; + optionBehaviour.gameObject.SetActive(enabledOrNotCollapsed); + if (enabledOrNotCollapsed) num -= 0.45f; } } @@ -379,7 +389,7 @@ public static class GameOptionsMenuPatch __instance.scrollBar.SetYBoundsMax(-num - 1.65f); } - private static BaseGameSetting GetSetting(OptionItem item) + public static BaseGameSetting GetSetting(OptionItem item) { BaseGameSetting baseGameSetting; @@ -815,7 +825,7 @@ public static class StringOptionPatch icon.SetAsLastSibling(); } - private static string GetGhostRoleTeam(CustomRoles role) + public static string GetGhostRoleTeam(CustomRoles role) { IGhostRole instance = GhostRolesManager.CreateGhostRoleInstance(role); if (instance == null) return string.Empty; @@ -994,9 +1004,9 @@ public static class GameSettingMenuPatch { try { - (OptionItem MinSetting, OptionItem MaxSetting) impLimits = Options.FactionMinMaxSettings[Team.Impostor]; - MinImpsOnOpen = impLimits.MinSetting.GetInt(); - MaxImpsOnOpen = impLimits.MaxSetting.GetInt(); + (OptionItem MinSetting, OptionItem MaxSetting) = Options.FactionMinMaxSettings[Team.Impostor]; + MinImpsOnOpen = MinSetting.GetInt(); + MaxImpsOnOpen = MaxSetting.GetInt(); NumImpsOnOpen = Main.NormalOptions.NumImpostors; VanillaKillCooldownOnOpen = Main.NormalOptions.KillCooldown; @@ -1025,21 +1035,7 @@ public static class GameSettingMenuPatch label.color = Color.white; button.activeTextColor = button.inactiveTextColor = Color.white; button.selectedTextColor = new(0.7f, 0.7f, 0.7f); - - Color color = tab switch - { - TabGroup.SystemSettings => new(0.2f, 0.2f, 0.2f), - TabGroup.GameSettings => new(0.2f, 0.4f, 0.3f), - TabGroup.TaskSettings => new(0.4f, 0.2f, 0.5f), - TabGroup.ImpostorRoles => new(0.5f, 0.2f, 0.2f), - TabGroup.CrewmateRoles => new(0.2f, 0.4f, 0.5f), - TabGroup.NeutralRoles => new(0.5f, 0.4f, 0.2f), - TabGroup.CovenRoles => new(0.5f, 0.2f, 0.4f), - TabGroup.Addons => new(0.4f, 0.2f, 0.3f), - TabGroup.OtherRoles => new(0.4f, 0.4f, 0.4f), - TabGroup.PresetExplorer => new(0.5f, 0.5f, 0.5f), - _ => new(0.3f, 0.3f, 0.3f) - }; + Color color = tab.GetTabColor(); button.inactiveSprites.GetComponent().color = color; button.activeSprites.GetComponent().color = color; @@ -1304,6 +1300,7 @@ public static class GameSettingMenuPatch result.ForEach(x => x.SetHidden(true)); + gameSettings.scrollBar.ScrollToTop(); GameOptionsMenuPatch.ReCreateSettings(gameSettings); textField.Clear(); } @@ -1459,12 +1456,12 @@ public static class GameSettingMenuPatch try { int numImpostors = Main.NormalOptions.NumImpostors; - (OptionItem MinSetting, OptionItem MaxSetting) impLimits = Options.FactionMinMaxSettings[Team.Impostor]; + (OptionItem MinSetting, OptionItem MaxSetting) = Options.FactionMinMaxSettings[Team.Impostor]; - if (numImpostors != NumImpsOnOpen && MinImpsOnOpen == impLimits.MinSetting.GetInt() && MaxImpsOnOpen == impLimits.MaxSetting.GetInt()) + if (numImpostors != NumImpsOnOpen && MinImpsOnOpen == MinSetting.GetInt() && MaxImpsOnOpen == MaxSetting.GetInt()) { - impLimits.MinSetting.SetValue(numImpostors); - impLimits.MaxSetting.SetValue(numImpostors); + MinSetting.SetValue(numImpostors); + MaxSetting.SetValue(numImpostors); Logger.SendInGame(string.Format(Translator.GetString("MinMaxModdedImpCountsSettingsChangedAuto"), numImpostors)); } @@ -1497,7 +1494,7 @@ public static class GameSettingMenuPatch ModSettingsTabs = []; GMButtons = []; - Main.Instance.StartCoroutine(OptionShower.GetText()); + //Main.Instance.StartCoroutine(OptionShower.GetText()); } } diff --git a/Patches/GameStartManagerPatch.cs b/Patches/GameStartManagerPatch.cs index aa1459fb6..2e717c637 100644 --- a/Patches/GameStartManagerPatch.cs +++ b/Patches/GameStartManagerPatch.cs @@ -137,7 +137,7 @@ public static class GameStartManagerPatch if (!AmongUsClient.Instance) return false; - if (AmongUsClient.Instance.AmHost) VanillaUpdate(__instance); + VanillaUpdate(__instance); if (AmongUsClient.Instance.IsGameStarted || GameStates.IsInGame || !__instance || __instance.startState == GameStartManager.StartingStates.Starting) return false; @@ -156,7 +156,7 @@ public static class GameStartManagerPatch } } - if (!AmongUsClient.Instance || !GameData.Instance || !AmongUsClient.Instance.AmHost) return true; + if (!AmongUsClient.Instance || !GameData.Instance) return true; CheckAutoStart(__instance); } @@ -239,7 +239,7 @@ public static class GameStartManagerPatch private static void VanillaUpdate(GameStartManager instance) { - if (!GameData.Instance || !GameManager.Instance || !AmongUsClient.Instance.AmHost) return; + if (!GameData.Instance || !GameManager.Instance) return; try { instance.UpdateMapImage((MapNames)GameManager.Instance.LogicOptions.MapId); } catch (Exception e) @@ -254,7 +254,7 @@ public static class GameStartManagerPatch } instance.CheckSettingsDiffs(); - instance.StartButton.gameObject.SetActive(true); + instance.StartButton.gameObject.SetActive(AmongUsClient.Instance.AmHost); instance.RulesPresetText.text = TranslationController.Instance.GetString(GameOptionsManager.Instance.CurrentGameOptions.GetRulesPresetTitle()); if (GameCode.IntToGameName(AmongUsClient.Instance.GameId) == null) instance.privatePublicPanelText.text = TranslationController.Instance.GetString(StringNames.LocalButton); @@ -320,13 +320,19 @@ public static class GameStartManagerPatch instance.GameStartText.text = string.Empty; } } - + if (!HudManager.InstanceExists) return; - if (instance.LobbyInfoPane.gameObject.activeSelf && HudManager.Instance.Chat.IsOpenOrOpening) - instance.LobbyInfoPane.DeactivatePane(); + if (instance.LobbyInfoPane.gameObject.activeSelf) + { + var lobbyViewSettingsPane = instance.LobbyInfoPane.LobbyViewSettingsPane; + lobbyViewSettingsPane.scrollBar.enabled = !HudManager.Instance.Chat.IsOpenOrOpening; + } - instance.LobbyInfoPane.gameObject.SetActive(!HudManager.Instance.Chat.IsOpenOrOpening); + //if (instance.LobbyInfoPane.gameObject.activeSelf && HudManager.Instance.Chat.IsOpenOrOpening) + // instance.LobbyInfoPane.DeactivatePane(); + + //instance.LobbyInfoPane.gameObject.SetActive(!HudManager.Instance.Chat.IsOpenOrOpening); } public static void Postfix(GameStartManager __instance) @@ -430,7 +436,7 @@ public static class GameStartManagerPatch tmp.alignment = TextAlignmentOptions.Center; tmp.color = Color.cyan; tmp.outlineColor = Color.black; - tmp.outlineWidth = 0.4f; + tmp.outlineWidth = LangHasSensitiveOutlineText() ? 0.1f : 0.4f; tmp.transform.localPosition += new Vector3(-0.625f, -0.12f, 0f); tmp.transform.localScale = new(0.6f, 0.6f, 1f); } diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 90a96a08b..0417c2bb7 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -63,11 +63,11 @@ internal static class HudManagerPatch SettingsText = null; } - if (SettingsText) - { - SettingsText.text = OptionShower.GetTextNoFresh(); - SettingsText.enabled = SettingsText.text != string.Empty; - } + //if (SettingsText) + //{ + // SettingsText.text = OptionShower.GetTextNoFresh(); + // SettingsText.enabled = SettingsText.text != string.Empty; + //} } else if (SettingsText) { diff --git a/Patches/LobbyViewSettingsPanePatch.cs b/Patches/LobbyViewSettingsPanePatch.cs new file mode 100644 index 000000000..bb2d3fddb --- /dev/null +++ b/Patches/LobbyViewSettingsPanePatch.cs @@ -0,0 +1,1081 @@ +using BepInEx.Unity.IL2CPP.Utils.Collections; +using EHR.Roles; +using HarmonyLib; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using TMPro; +using UnityEngine; +using UnityEngine.Events; + +namespace EHR.Patches; + +[HarmonyPatch(typeof(LobbyViewSettingsPane))] +public static class LobbyViewSettingsPanePatch +{ + private static StringNames VanillaSettingsTabName => StringNames.OverviewCategory; + private static StringNames VanillaRolesTabName => StringNames.RolesCategory; + + private static StringNames LastTabPressed = StringNames.OverviewCategory; + public static CustomGameMode LastGameModeSelected = CustomGameMode.Standard; + private static Coroutine RoleListCoroutine; + private static Coroutine OptionsCoroutine; + + private static PassiveButton ShowOnlyEnabledRolesButton; + private static bool OnlyEnabledRoles = false; + + private static readonly Dictionary TabButtons = []; + private static readonly Dictionary TabNames = []; + private static readonly Dictionary AllTabButtons = []; + private static readonly HashSet RoleEnabledList = []; + private static readonly List CahedRoleEnabledList = []; + + [HarmonyPatch(nameof(LobbyViewSettingsPane.Awake))] + [HarmonyPostfix] + public static void Awake_Postfix(LobbyViewSettingsPane __instance) + { + __instance.StartCoroutine(CoAwakeViwer().WrapToIl2Cpp()); + return; + + IEnumerator CoAwakeViwer() + { + var background = __instance.transform.FindChild("Background"); + var backgroundShine = __instance.transform.FindChild("Background Shine"); + var gameModeTextTransform = __instance.gameModeText.transform; + var divider = __instance.transform.FindChild("Divider"); + var tabBackground = __instance.transform.FindChild("TabBackground"); + var headerImage = __instance.transform.FindChild("HeaderImage"); + var overviewTab = __instance.transform.FindChild("OverviewTab"); + var roleTab = __instance.transform.FindChild("RolesTabs"); + var mainAreaTransform = __instance.transform.FindChild("MainArea"); + var maskBg = __instance.backgroundMask.transform; + + yield return null; + + // #### Resize the lobby view window #### + + background.localPosition = new(-0.619f, -0.5462f, 12f); + background.localScale = new(1.0141f, 1.6141f, 1.041f); + + backgroundShine.localPosition = new(-0.5876f, -1.58f, -0.1f); + backgroundShine.localScale = new(1.36f, 2.21f, 1.0141f); + + gameModeTextTransform.localPosition = new(-2.65f, 3.85f, -2f); + gameModeTextTransform.localScale = new(0.9f, 0.9f, 1f); + + divider.localPosition = new(-0.6377f, 3.382f, -0.1f); + divider.localScale = new(1.07f, 1f, 1f); + + tabBackground.localPosition = new(-0.72f, 2.75f, 2f); + tabBackground.localScale = new(12.42f, 1.2528f, 1f); + + headerImage.localPosition = new(2.88f, 3.86f, 11.7864f); + headerImage.localScale = new(0.3653f, 0.3653f, 0.5053f); + + overviewTab.localPosition = new(-5.65f, 3.1f, 0f); + overviewTab.localScale = new(0.7f, 0.7f, 1f); + + roleTab.localPosition = new(-3.2f, 3.1f, -0f); + roleTab.localScale = new(0.7f, 0.7f, 1f); + + mainAreaTransform.localPosition = new(0.76f, 0.3f, -1f); + mainAreaTransform.localScale = new(1.02f, 1f, 1f); + + maskBg.localPosition = new(-1.4794f, -2.0039f, -0.1f); + maskBg.localScale = new(12.4155f, 7.2925f, 1f); + + yield return null; + + // #### Patch info panel origin #### + var viewSettingsInfoPanel = __instance.infoPanelOrigin; + + // Change Title Text + var titleText = viewSettingsInfoPanel.titleText; + titleText.alignment = TextAlignmentOptions.Left; + titleText.fontSizeMin = 1f; + titleText.margin = new Vector4(-1f, 0.0008f, 0f, 0f); + titleText.transform.localPosition = new Vector3(0.02f, 0f, -2f); + + // Change label background + var labelBackground = viewSettingsInfoPanel.labelBackground.transform; + labelBackground.localPosition = new(-0.5325f, 0f, 0); + labelBackground.localScale = new(1.22f, 1f, 1f); + //labelBackground.color = new(0.6f, 0.6f, 0.6f); // Also changed vanilla label background + + // Change value size + var spritePanel = viewSettingsInfoPanel.transform.FindChild("Value")?.transform.FindChild("Sprite"); + spritePanel.localPosition = new(2f, 0f, 0); + spritePanel.localScale = new(0.35f, 0.6f, 1f); + + var posPanel = viewSettingsInfoPanel.settingText.transform; + posPanel.localPosition = new(2f, 0f, -2f); + posPanel.localScale = new(0.7f, 0.7f, 1f); + + viewSettingsInfoPanel.checkMark.sprite = Utils.LoadSprite("EHR.Resources.Images.Checkmark.png", 100f); + var checkMarkOn = viewSettingsInfoPanel.checkMark.transform; + checkMarkOn.localPosition = new(2f, 0f, -2f); + checkMarkOn.localScale = new(0.8f, 0.8f, 1f); + viewSettingsInfoPanel.checkMark.color = new Color32(0, 165, 255, 255); + + viewSettingsInfoPanel.checkMarkOff.sprite = Utils.LoadSprite("EHR.Resources.Images.CheckMarkOff.png", 100f); + var checkMarkOff = viewSettingsInfoPanel.checkMarkOff.transform; + checkMarkOff.localPosition = new(2f, 0f, -2f); + checkMarkOff.localScale = new(0.8f, 0.8f, 1f); + viewSettingsInfoPanel.checkMarkOff.color = Color.red; + + yield return null; + + __instance.transform.FindChild("ClickToClose").transform.FindChild("IgnoreClose").localScale = new(1f, 2f, 1f); + + // #### Set colors for vanilla setting tab #### + __instance.taskTabButton.activeTextColor = __instance.taskTabButton.inactiveTextColor = Color.white; + __instance.taskTabButton.selectedTextColor = Color.gray; + __instance.taskTabButton.inactiveSprites.GetComponent().color = Color.black; + __instance.taskTabButton.activeSprites.GetComponent().color = new(0.2f, 0.2f, 0.2f); + __instance.taskTabButton.selectedSprites.GetComponent().color = new(0.1f, 0.1f, 0.1f); + __instance.taskTabButton.inactiveSprites.GetComponent().sprite = Utils.LoadSprite("EHR.Resources.Images.DefaultPlate.png", 135f); + __instance.taskTabButton.inactiveSprites.transform.FindChild("Shine").gameObject.SetActive(false); + __instance.taskTabButton.activeSprites.transform.FindChild("Shine").gameObject.SetActive(false); + __instance.taskTabButton.selectedSprites.transform.FindChild("Shine").gameObject.SetActive(false); + yield return null; + + // #### Set colors for role tab #### + __instance.rolesTabButton.activeTextColor = __instance.rolesTabButton.inactiveTextColor = Color.white; + __instance.rolesTabButton.selectedTextColor = Color.gray; + //__instance.rolesTabButton.inactiveSprites.GetComponent().color = Color.black; + //__instance.rolesTabButton.activeSprites.GetComponent().color = Color.gray; + //__instance.rolesTabButton.selectedSprites.GetComponent().color = Color.black; + __instance.rolesTabButton.inactiveSprites.GetComponent().sprite = Utils.LoadSprite("EHR.Resources.Images.DefaultPlate.png", 135f); + //__instance.rolesTabButton.activeSprites.GetComponent().sprite = CustomButton.Get("GuessPlate"); + //__instance.rolesTabButton.selectedSprites.GetComponent().sprite = CustomButton.Get("GuessPlate"); + __instance.rolesTabButton.inactiveSprites.transform.FindChild("Shine").gameObject.SetActive(false); + __instance.rolesTabButton.activeSprites.transform.FindChild("Shine").gameObject.SetActive(false); + __instance.rolesTabButton.selectedSprites.transform.FindChild("Shine").gameObject.SetActive(false); + yield return null; + + // #### Patch info panel role origin #### + var panelRole = __instance.infoPanelRoleOrigin; + var panelRoleTransform = panelRole.transform; + + // Role name + panelRole.titleText.transform.localScale = new(1.7f, 1.7f, 1f); + panelRole.titleText.transform.localPosition = new(-2.7f, 0f, -2f); + panelRole.titleText.alignment = TextAlignmentOptions.Left; + panelRole.titleText.enableWordWrapping = false; + panelRole.titleText.overflowMode = TextOverflowModes.Overflow; + panelRole.titleText.fontWeight = FontWeight.Black; + panelRole.titleText.outlineColor = Color.black; + panelRole.titleText.outlineWidth = Translator.LangHasSensitiveOutlineText() ? 0.09f : 0.23f; + panelRole.titleText.color = Color.white; + + // "% Chance" title text + panelRole.chanceTitle.alignment = TextAlignmentOptions.Left; + panelRole.chanceTitle.enableWordWrapping = false; + panelRole.chanceTitle.overflowMode = TextOverflowModes.Overflow; + panelRole.chanceTitle.fontWeight = FontWeight.Black; + panelRole.chanceTitle.outlineColor = Color.black; + panelRole.chanceTitle.outlineWidth = Translator.LangHasSensitiveOutlineText() ? 0.09f : 0.2f; + panelRole.chanceTitle.color = Color.white; + panelRole.chanceTitle.transform.localPosition = new(5.15f, -0.02f, -2f); + panelRole.chanceTitle.transform.localScale = new(1.1f, 1.1f, 1f); + + // Chance value + panelRole.chanceText.fontWeight = FontWeight.Black; + panelRole.chanceText.outlineColor = Color.black; + panelRole.chanceText.outlineWidth = 0.26f; + panelRole.chanceText.color = Color.white; + panelRole.transform.FindChild("Chance")?.localPosition = new(2.5f, -0.02f, -1f); + + // Max count sprite + panelRole.transform.FindChild("Value")?.localPosition = new(0.35f, -0.02f, -1f); + + // Max count value + panelRole.settingText.fontWeight = FontWeight.Black; + panelRole.settingText.outlineColor = Color.black; + panelRole.settingText.outlineWidth = 0.2f; + panelRole.settingText.color = Color.white; + + yield return null; + + // #### Patch category header role origin #### + var categoryHeaderRoleTitle = __instance.categoryHeaderRoleOrigin.Title; + + categoryHeaderRoleTitle.fontWeight = FontWeight.Black; + categoryHeaderRoleTitle.outlineColor = Color.white; + categoryHeaderRoleTitle.outlineWidth = Translator.LangHasSensitiveOutlineText() ? 0.09f : 0.2f; + + yield return null; + + // #### Patch advanced role panel origin #### + var advancedRolePanelTitle = __instance.advancedRolePanelOrigin.header.Title; + var advancedRolePanelTitleTransform = advancedRolePanelTitle.transform; + + advancedRolePanelTitle.fontWeight = FontWeight.Black; + advancedRolePanelTitle.outlineColor = Color.black; + advancedRolePanelTitle.outlineWidth = Translator.LangHasSensitiveOutlineText() ? 0.067f : 0.2f; + advancedRolePanelTitleTransform.localScale = new(1.3f, 1.3f, 1f); + advancedRolePanelTitleTransform.localPosition = new(-2.3f, -0.15f, -1f); + yield return null; + + __instance.taskTabButton.buttonText.text = Translator.GetString("TabGroup.VanillaSettings"); + __instance.rolesTabButton.transform.localPosition = new(-5.65f, 2.5f, 0); + + TabNames.Clear(); + TabButtons.Clear(); + AllTabButtons.Clear(); + + TabButtons[VanillaSettingsTabName] = __instance.taskTabButton; + TabButtons[VanillaRolesTabName] = __instance.taskTabButton; + yield return null; + + // Change game mode text & position + __instance.gameModeText.DestroyTranslator(); + __instance.gameModeText.text = Translator.GetString(Options.CurrentGameMode.ToString()); + __instance.gameModeText.color = Main.GameModeColors[Options.CurrentGameMode]; + LastGameModeSelected = Options.CurrentGameMode; + yield return null; + + // Create button "Show Only Enabled Roles" + ShowOnlyEnabledRolesButton = Object.Instantiate(__instance.rolesTabButton, __instance.rolesTabButton.transform.parent); + ShowOnlyEnabledRolesButton.buttonText.DestroyTranslator(); + ShowOnlyEnabledRolesButton.name = "ShowOnlyEnabledRolesButton"; + ShowOnlyEnabledRolesButton.buttonText.text = OnlyEnabledRoles + ? Translator.GetString($"LobbyViewSettings_ShowAlldRolesButtonText") + : Translator.GetString($"LobbyViewSettings_ShowOnlyEnabledRolesButtonText"); + + ShowOnlyEnabledRolesButton.activeTextColor = ShowOnlyEnabledRolesButton.inactiveTextColor = Color.white; + ShowOnlyEnabledRolesButton.selectedTextColor = new(0.7f, 0.7f, 0.7f); + + ShowOnlyEnabledRolesButton.inactiveSprites.GetComponent().color = Color.cyan; + ShowOnlyEnabledRolesButton.activeSprites.GetComponent().color = Color.cyan; + ShowOnlyEnabledRolesButton.selectedSprites.GetComponent().color = Color.cyan; + + ShowOnlyEnabledRolesButton.OnClick = new(); + ShowOnlyEnabledRolesButton.OnClick.AddListener((UnityAction)(() => + { + OnlyEnabledRoles = !OnlyEnabledRoles; + + ShowOnlyEnabledRolesButton.buttonText.text = OnlyEnabledRoles + ? Translator.GetString($"LobbyViewSettings_ShowAlldRolesButtonText") + : Translator.GetString($"LobbyViewSettings_ShowOnlyEnabledRolesButtonText"); + + ShowOnlyEnabledRolesButton.SelectButton(OnlyEnabledRoles); + + __instance?.ReDrawTab(LastTabPressed); + })); + + ShowOnlyEnabledRolesButton.SelectButton(OnlyEnabledRoles); + ShowOnlyEnabledRolesButton.transform.localScale = new Vector3(0.8f, 0.8f, 1f); + ShowOnlyEnabledRolesButton.transform.localPosition = new Vector3(7.23f, -3.45f, -2f); + ShowOnlyEnabledRolesButton.gameObject.SetActive(false); + yield return null; + + // Create right arrow button + var rightButton = Object.Instantiate(__instance.BackButton, __instance.BackButton.transform.parent).gameObject; + var rightButtonBoxCollider2D = rightButton.GetComponent(); + rightButtonBoxCollider2D.size = new Vector2(0.3f, 0.3f); + rightButtonBoxCollider2D.offset = new Vector2(0f, 0f); + + rightButton.transform.localPosition = new Vector3(-5.5f, 3.85f, -2f); + rightButton.transform.localScale = new Vector3(3f, 3f, 2f); + rightButton.name = "RightButtonArrow"; + + var rightButtonInactiveSprite = rightButton.transform.FindChild("Normal").GetComponentInChildren(); + rightButtonInactiveSprite.transform.localPosition = new Vector3(0f, 0f, 0.3f); + rightButtonInactiveSprite.sprite = Utils.LoadSprite("EHR.Resources.Images.InactiveNextButton.png", 100f); + + var rightButtonActiveSprite = rightButton.transform.FindChild("Hover").GetComponentInChildren(); + rightButtonActiveSprite.transform.localPosition = new Vector3(0f, 0f, 0.3f); + rightButtonActiveSprite.sprite = Utils.LoadSprite("EHR.Resources.Images.ActiveNextButton.png", 100f); + + var rightPassiveButton = rightButton.gameObject.GetComponent(); + rightPassiveButton.OnClick = new(); + rightPassiveButton.OnClick.AddListener((UnityAction)(() => + { + LastGameModeSelected++; + var enumGameModes = Enum.GetValues().Without(CustomGameMode.All).ToArray(); + if ((int)LastGameModeSelected > enumGameModes.Length) + { + LastGameModeSelected = CustomGameMode.Standard; + } + __instance.ChangeTab(VanillaSettingsTabName); + + })); + yield return null; + + // Create left arrow button + var leftButton = Object.Instantiate(rightButton, __instance.BackButton.transform.parent).gameObject; + leftButton.transform.localPosition = new Vector3(-6.4f, 3.85f, -2f); + leftButton.name = "LeftButtonArrow"; + // flip button + leftButton.transform.FindChild("Normal").gameObject.GetComponentInChildren().flipX = true; + leftButton.transform.FindChild("Hover").gameObject.GetComponentInChildren().flipX = true; + + var leftButtonPassiveButton = leftButton.gameObject.GetComponent(); + leftButtonPassiveButton.OnClick = new(); + leftButtonPassiveButton.OnClick.AddListener((UnityAction)(() => + { + LastGameModeSelected--; + var enumGameModes = Enum.GetValues().Without(CustomGameMode.All).ToArray(); + if ((int)LastGameModeSelected < 0x01) + { + LastGameModeSelected = (CustomGameMode)enumGameModes.Length; + } + __instance.ChangeTab(VanillaSettingsTabName); + })); + yield return null; + + + // #### Add Tab Group #### + + // Started vanilla tab button positions: + // taskTabButton - x: -5.65 - y: 3.1 - z: 0 + // rolesTabButton - x: -3.2 - y: 3.1 - z: 0 + + // x: +2.45 + // y: -0.6 + + int indexSettings = 1; + int indexRoles = 0; + foreach (var tabGroup in Enum.GetValues()) + { + Vector3 newXPos; + var stringName = (StringNames)(5000 + tabGroup); + TabNames[stringName] = tabGroup; + Color color = tabGroup.GetTabColor(); + + switch (tabGroup) + { + case TabGroup.SystemSettings: + case TabGroup.GameSettings: + case TabGroup.TaskSettings: + var cloneSettingTabButton = Object.Instantiate(__instance.taskTabButton, __instance.taskTabButton.transform.parent); + cloneSettingTabButton.buttonText.DestroyTranslator(); + cloneSettingTabButton.name = tabGroup.ToString(); + cloneSettingTabButton.buttonText.text = Translator.GetString($"TabGroup.{tabGroup}"); + + newXPos = cloneSettingTabButton.transform.localPosition; + newXPos.x += 2.45f * indexSettings; + cloneSettingTabButton.transform.localPosition = newXPos; + + cloneSettingTabButton.activeTextColor = cloneSettingTabButton.inactiveTextColor = Color.white; + cloneSettingTabButton.selectedTextColor = new(0.7f, 0.7f, 0.7f); + + cloneSettingTabButton.inactiveSprites.GetComponent().color = color; + cloneSettingTabButton.activeSprites.GetComponent().color = color; + cloneSettingTabButton.selectedSprites.GetComponent().color = color; + + cloneSettingTabButton.OnClick = new(); + cloneSettingTabButton.OnClick.AddListener((UnityAction)(() => + { + __instance.ChangeTab(stringName); + })); + + TabButtons[stringName] = cloneSettingTabButton; + AllTabButtons[tabGroup] = cloneSettingTabButton; + indexSettings++; + break; + case TabGroup.ImpostorRoles: + case TabGroup.CrewmateRoles: + case TabGroup.NeutralRoles: + case TabGroup.CovenRoles: + case TabGroup.Addons: + case TabGroup.OtherRoles: + var cloneRoleTabButton = Object.Instantiate(__instance.rolesTabButton, __instance.rolesTabButton.transform.parent); + cloneRoleTabButton.buttonText.DestroyTranslator(); + cloneRoleTabButton.name = tabGroup.ToString(); + cloneRoleTabButton.buttonText.text = Translator.GetString($"TabGroup.{tabGroup}"); + + if (indexRoles != 0) + { + newXPos = cloneRoleTabButton.transform.localPosition; + newXPos.x += 2.45f * indexRoles; + + if (tabGroup is TabGroup.Addons) + newXPos.y += 0.6f; + else + indexRoles++; + + cloneRoleTabButton.transform.localPosition = newXPos; + } + else indexRoles++; + + cloneRoleTabButton.activeTextColor = cloneRoleTabButton.inactiveTextColor = Color.white; + cloneRoleTabButton.selectedTextColor = new(0.7f, 0.7f, 0.7f); + + cloneRoleTabButton.inactiveSprites.GetComponent().color = color; + cloneRoleTabButton.activeSprites.GetComponent().color = color; + cloneRoleTabButton.selectedSprites.GetComponent().color = color; + + cloneRoleTabButton.OnClick = new(); + cloneRoleTabButton.OnClick.AddListener((UnityAction)(() => + { + __instance.ChangeTab(stringName); + })); + + TabButtons[stringName] = cloneRoleTabButton; + AllTabButtons[tabGroup] = cloneRoleTabButton; + break; + } + yield return null; + } + __instance.rolesTabButton.gameObject.SetActive(false); // Hide vanilla role tab + + __instance.scrollBar.ContentXBounds.max = 1f; + __instance.scrollBar.SetYBoundsMax(-2f); + } + } + [HarmonyPatch(nameof(LobbyViewSettingsPane.OnEnable))] + [HarmonyPostfix] + public static void OnEnable_Postfix(LobbyViewSettingsPane __instance) + { + LateTask.New(() => + { + __instance.taskTabButton.activeTextColor = __instance.taskTabButton.inactiveTextColor = Color.white; + __instance.taskTabButton.selectedTextColor = Color.gray; + __instance.taskTabButton.inactiveSprites.GetComponent().color = Color.black; + __instance.taskTabButton.activeSprites.GetComponent().color = new(0.2f, 0.2f, 0.2f); + __instance.taskTabButton.selectedSprites.GetComponent().color = new(0.1f, 0.1f, 0.1f); + + LastGameModeSelected = Options.CurrentGameMode; + + __instance.ChangeTab(LastTabPressed); + }, 0.3f, "ChangeTab", log: false); + } + [HarmonyPatch(nameof(LobbyViewSettingsPane.SetTab))] + [HarmonyPrefix] + public static bool SetTab_Prefix(LobbyViewSettingsPane __instance) + { + if (__instance.currentTab == VanillaRolesTabName) + { + __instance.rolesTabButton.SelectButton(true); + __instance.taskTabButton.SelectButton(false); + __instance.DrawRolesTab(); + return false; + } + if (__instance.currentTab == VanillaSettingsTabName) + { + __instance.taskTabButton.SelectButton(true); + __instance.rolesTabButton.SelectButton(false); + __instance.DrawNormalTab(); + return false; + } + __instance.taskTabButton.SelectButton(false); + __instance.rolesTabButton.SelectButton(false); + return false; + } + + [HarmonyPatch(nameof(LobbyViewSettingsPane.DrawNormalTab))] + [HarmonyPrefix] + public static bool DrawNormalTab_Prefix(LobbyViewSettingsPane __instance) + { + if (__instance == null) return true; + + __instance.taskTabButton.inactiveTextColor = Color.white; + __instance.taskTabButton.selectedTextColor = Color.gray; + + try + { + if (ShowOnlyEnabledRolesButton != null && ShowOnlyEnabledRolesButton.gameObject != null) + ShowOnlyEnabledRolesButton.gameObject.SetActive(false); + } + catch { } + + return __instance.currentTab == VanillaSettingsTabName; + } + + [HarmonyPatch(nameof(LobbyViewSettingsPane.DrawRolesTab))] + [HarmonyPrefix] + public static bool DrawRolesTab_Prefix(LobbyViewSettingsPane __instance) + { + __instance.rolesTabButton.inactiveTextColor = Color.white; + return __instance.currentTab == VanillaRolesTabName; + } + + private static void ReDrawTab(this LobbyViewSettingsPane viewSettings, StringNames tabName) + { + viewSettings.currentTab = tabName; + for (int i = 0; i < viewSettings.settingsInfo.Count; i++) + { + Object.Destroy(viewSettings.settingsInfo[i].gameObject); + } + viewSettings.settingsInfo.Clear(); + SetTabPatch_Postfix(viewSettings); + } + private static void HideTab(TabGroup tabName, PassiveButton buttonTab) + { + try + { + if (buttonTab.gameObject == null) return; + + var currentGameMode = LastGameModeSelected; + buttonTab.gameObject.SetActive(true); + + switch (currentGameMode) + { + case CustomGameMode.Standard: + buttonTab.gameObject.SetActive(true); + break; + case CustomGameMode.HideAndSeek: + if (tabName is TabGroup.CovenRoles or TabGroup.Addons or TabGroup.OtherRoles) + buttonTab.gameObject.SetActive(false); + break; + default: + if (tabName is TabGroup.ImpostorRoles + or TabGroup.CrewmateRoles + or TabGroup.NeutralRoles + or TabGroup.CovenRoles + or TabGroup.Addons + or TabGroup.OtherRoles) + { + buttonTab.gameObject.SetActive(false); + } + break; + } + } + catch { } + } + + [HarmonyPatch(nameof(LobbyViewSettingsPane.ChangeTab))] + [HarmonyPatch(nameof(LobbyViewSettingsPane.RefreshTab))] + [HarmonyPostfix] + public static void SetTabPatch_Postfix(LobbyViewSettingsPane __instance) + { + LastTabPressed = __instance.currentTab; + __instance.gameModeText.text = Translator.GetString(LastGameModeSelected.ToString()); + __instance.gameModeText.color = Main.GameModeColors[LastGameModeSelected]; + + __instance.taskTabButton.SelectButton(false); + __instance.rolesTabButton.SelectButton(false); + + foreach (var tabButton in AllTabButtons) + { + var tabGroup = tabButton.Key; + var passiveButton = tabButton.Value; + + passiveButton.SelectButton(false); + HideTab(tabGroup, passiveButton); + } + + if (__instance.currentTab == VanillaSettingsTabName) + { + __instance.taskTabButton.SelectButton(true); + __instance.scrollBar.SetYBoundsMax(4.2f); + } + else if (TabNames.TryGetValue(__instance.currentTab, out var tab) + && TabButtons.TryGetValue(__instance.currentTab, out var button)) + { + button.SelectButton(true); + + switch (tab) + { + case TabGroup.SystemSettings: + case TabGroup.GameSettings: + case TabGroup.TaskSettings: + DrawOptions(__instance, tab); + break; + case TabGroup.ImpostorRoles: + case TabGroup.CrewmateRoles: + case TabGroup.NeutralRoles: + case TabGroup.CovenRoles: + case TabGroup.Addons: + case TabGroup.OtherRoles: + DrawRoles(__instance, tab); + break; + } + } + } + private static void DrawOptions(LobbyViewSettingsPane viewSettings, TabGroup tabName) + { + float xPos; + float yPos = 1.44f; + bool firstTitle = true; + int index = 0; + TextOptionItem header = null; + + if (ShowOnlyEnabledRolesButton?.gameObject != null) + ShowOnlyEnabledRolesButton.gameObject.SetActive(false); + + if (OptionsCoroutine != null) viewSettings.StopCoroutine(OptionsCoroutine); + OptionsCoroutine = viewSettings.StartCoroutine(CoDrawOptions().WrapToIl2Cpp()); + return; + + IEnumerator CoDrawOptions() + { + foreach (OptionItem option in OptionItem.AllOptions) + { + if (option.Tab != tabName) continue; + BaseGameSetting data = GameOptionsMenuPatch.GetSetting(option); + + bool enabledOrNotCollapsed = !option.IsCurrentlyHidden(forLobbyView: true) && AllParentsEnabledAndVisible(option.Parent, checkCollapsedSection: true); + // Title + if (data == null && option is TextOptionItem toi) + { + if (!firstTitle && enabledOrNotCollapsed) + { + yPos -= 0.92f; + } + firstTitle = false; + CategoryHeaderMasked categoryHeaderMasked = Object.Instantiate(viewSettings.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, viewSettings.settingsContainer); + categoryHeaderMasked.SetHeader(StringNames.Name, 61); + categoryHeaderMasked.Background.color = categoryHeaderMasked.Divider.color = option.NameColor; + categoryHeaderMasked.Title.text = option.GetName(disableColor: true).Trim('★', ' ').RemoveHtmlTags(); + categoryHeaderMasked.Title.name = option.Name; + categoryHeaderMasked.transform.localScale = Vector3.one; + categoryHeaderMasked.transform.localPosition = new Vector3(-9.77f, yPos, -2f); + + var chmCollider = categoryHeaderMasked.gameObject.AddComponent(); + chmCollider.size = new Vector2(7, 0.7f); + chmCollider.offset = new Vector2(1.5f, -0.3f); + var chmButton = categoryHeaderMasked.gameObject.AddComponent(); + chmButton.ClickSound = viewSettings.BackButton.GetComponent().ClickSound; + chmButton.OnMouseOver = new(); + chmButton.OnMouseOut = new(); + chmButton.OnClick = new(); + chmButton.OnClick.AddListener((UnityAction)(() => + { + toi.CollapsesSection = !toi.CollapsesSection; + viewSettings.ReDrawTab(LastTabPressed); + })); + chmButton.SetButtonEnableState(true); + categoryHeaderMasked.gameObject.SetActive(enabledOrNotCollapsed); + + viewSettings.settingsInfo.Add(categoryHeaderMasked.gameObject); + if (enabledOrNotCollapsed) + { + if (!toi.CollapsesSection) yPos -= 1.05f; + else yPos += 0.25f; + } + index = 0; + header = toi; + yield return null; + continue; + } + else if (enabledOrNotCollapsed) + { + if (header != null) option.Header = header; + + ViewSettingsInfoPanel viewSettingsInfoPanel = Object.Instantiate(viewSettings.infoPanelOrigin, Vector3.zero, Quaternion.identity, viewSettings.settingsContainer); + viewSettingsInfoPanel.name = option.Name; + viewSettingsInfoPanel.transform.localScale = Vector3.one; + + if (firstTitle && index == 0) + { + firstTitle = false; + yPos -= 0.70f; + } + + if (index % 2 == 0) + { + xPos = -8.95f; + if (index > 0) yPos -= 0.95f; + } + else xPos = -3f; + + viewSettingsInfoPanel.transform.localPosition = new Vector3(xPos, yPos, -2f); + switch (data.Type) + { + case OptionTypes.Checkbox: + viewSettingsInfoPanel.SetInfoCheckbox(data.Title, 61, option.GetBool()); + Color32 color = LastGameModeSelected == CustomGameMode.Standard ? tabName switch + { + TabGroup.ImpostorRoles => new Color32(255, 25, 25, 255), + TabGroup.CrewmateRoles => new Color32(140, 255, 255, 255), + TabGroup.NeutralRoles => new Color32(255, 171, 27, 255), + TabGroup.CovenRoles => new Color32(123, 63, 187, 255), + _ => new Color32(0, 165, 255, 255) + } : Main.GameModeColors.TryGetValue(LastGameModeSelected, out var c) ? c : new Color32(0, 165, 255, 255); + viewSettingsInfoPanel.checkMark.color = color; + break; + case OptionTypes.String: + viewSettingsInfoPanel.SetInfo(data.Title, option.GetString(), 61); + break; + case OptionTypes.Float: + viewSettingsInfoPanel.SetInfo(data.Title, data.GetValueString(option.GetFloat()), 61); + break; + case OptionTypes.Int: + viewSettingsInfoPanel.SetInfo(data.Title, data.GetValueString(option.GetInt()), 61); + break; + default: + viewSettingsInfoPanel.SetInfo(data.Title, option.GetString(), 61); + break; + } + viewSettingsInfoPanel.titleText.text = option.GetName(); + viewSettings.settingsInfo.Add(viewSettingsInfoPanel.gameObject); + + Color labelColor = new(0.6f, 0.6f, 0.6f); + if (option.Parent?.Parent?.Parent != null) labelColor = new(0.6f, 0f, 0f); + else if (option.Parent?.Parent != null) labelColor = new(0.6f, 0.6f, 0f); + else if (option.Parent != null) labelColor = new(0f, 0f, 0.6f); + + viewSettingsInfoPanel.labelBackground.color = labelColor; + index++; + } + viewSettings.scrollBar.SetYBoundsMax(-yPos - 6f); + } + yPos -= 0.85f; + viewSettings.scrollBar.SetYBoundsMax(-yPos - 6f); + } + } + + private static void DrawRoles(LobbyViewSettingsPane viewSettings, TabGroup tabName) + { + float yPos = 1.3f; + float xPos = -6.53f; + RoleEnabledList.Clear(); + var allCustomRoles = Enum.GetValues(); + Color roleColorHeaderOrigin = tabName switch + { + TabGroup.ImpostorRoles => new(1f, 0f, 0f), + TabGroup.CrewmateRoles => new(0f, 0.7f, 1f), + TabGroup.NeutralRoles => new(1f, 1f, 0f), + TabGroup.CovenRoles => new(0.79f, 0.192f, 0.541f), + TabGroup.Addons => new(1f, 0f, 1f), + TabGroup.OtherRoles => new(0.4f, 0.4f, 0.4f), + _ => new(0.3f, 0.3f, 0.3f) + }; + Color roleColorHeaderRole = tabName.GetTabColor(); + TextOptionItem header = null; + + CategoryHeaderMasked categoryHeaderMasked = Object.Instantiate(viewSettings.categoryHeaderOrigin, viewSettings.settingsContainer); + categoryHeaderMasked.SetHeader(StringNames.RoleQuotaLabel, 61); + categoryHeaderMasked.Title.text = Translator.GetString($"TabGroup.{tabName}").Trim('★', ' ').RemoveHtmlTags(); + categoryHeaderMasked.Title.fontWeight = FontWeight.Light; + categoryHeaderMasked.Title.outlineColor = Color.white; + categoryHeaderMasked.Title.outlineWidth = Translator.LangHasSensitiveOutlineText() ? 0.09f : 0.4f; + categoryHeaderMasked.Background.color = roleColorHeaderOrigin; + categoryHeaderMasked.Title.color = Color.white; + categoryHeaderMasked.transform.localScale = Vector3.one; + categoryHeaderMasked.transform.localPosition = new Vector3(-9.77f, yPos, -2f); + viewSettings.settingsInfo.Add(categoryHeaderMasked.gameObject); + + if (ShowOnlyEnabledRolesButton?.gameObject != null) + { + Color color = tabName.GetTabColor(); + ShowOnlyEnabledRolesButton.inactiveSprites.GetComponent().color = color; + ShowOnlyEnabledRolesButton.activeSprites.GetComponent().color = color; + ShowOnlyEnabledRolesButton.selectedSprites.GetComponent().color = color; + ShowOnlyEnabledRolesButton.gameObject.SetActive(true); + } + + if (RoleListCoroutine != null) viewSettings.StopCoroutine(RoleListCoroutine); + RoleListCoroutine = viewSettings.StartCoroutine(CoDrawRoleList().WrapToIl2Cpp()); + return; + + IEnumerator CoDrawRoleList() + { + foreach (OptionItem option in OptionItem.AllOptions) + { + if (option.Tab != tabName) continue; + if (option.GameMode is not CustomGameMode.All && option.GameMode != LastGameModeSelected) continue; + + bool enabledOrNotCollapsed = !option.IsCurrentlyHidden(forLobbyView: true) && AllParentsEnabledAndVisible(option.Parent, checkCollapsedSection: true); + bool enabled = !option.IsCurrentlyHidden(forLobbyView: true, checkCollapsedSection: false) && AllParentsEnabledAndVisible(option.Parent, checkCollapsedSection: false); + BaseGameSetting data = GameOptionsMenuPatch.GetSetting(option); + string titleName = option.GetName(disableColor: true).Trim('★', ' ').RemoveHtmlTags(); + string realName = option.Name; + + // Title + if (data == null && option is TextOptionItem toi) + { + CategoryHeaderRoleVariant categoryHeaderRoleVariant = Object.Instantiate(viewSettings.categoryHeaderRoleOrigin, viewSettings.settingsContainer); + categoryHeaderRoleVariant.SetHeader((tabName is TabGroup.ImpostorRoles) ? StringNames.ImpostorRolesHeader : StringNames.CrewmateRolesHeader, 61); + categoryHeaderRoleVariant.name = realName; + + categoryHeaderRoleVariant.Title.text = titleName; + categoryHeaderRoleVariant.Title.color = Color.white; + categoryHeaderRoleVariant.Background.color = roleColorHeaderRole; + + if (enabled) yPos -= 0.4f; + categoryHeaderRoleVariant.transform.localScale = Vector3.one; + categoryHeaderRoleVariant.transform.localPosition = new Vector3(0.09f, yPos, -2f); + + var chmCollider = categoryHeaderRoleVariant.gameObject.AddComponent(); + chmCollider.size = new Vector2(4, 0.5f); + chmCollider.offset = new Vector2(-2.1f, -0.2f); + var chmButton = categoryHeaderRoleVariant.gameObject.AddComponent(); + chmButton.ClickSound = viewSettings.BackButton.GetComponent().ClickSound; + chmButton.OnMouseOver = new(); + chmButton.OnMouseOut = new(); + chmButton.OnClick = new(); + chmButton.OnClick.AddListener((UnityAction)(() => + { + toi.CollapsesSection = !toi.CollapsesSection; + viewSettings.ReDrawTab(LastTabPressed); + })); + chmButton.SetButtonEnableState(true); + categoryHeaderRoleVariant.gameObject.SetActive(enabled); + + viewSettings.settingsInfo.Add(categoryHeaderRoleVariant.gameObject); + if (enabled) + { + if (toi.CollapsesSection) yPos -= 0.1f; + else yPos -= 0.65f; + } + header = toi; + yield return null; + } + // Roles + if (allCustomRoles.FindFirst(x => x.ToString() == realName, out CustomRoles role)) + { + if (role == default || role is CustomRoles.CovenLeader) continue; + + try + { + option.Header = header; + + int chancePerGame = Options.CustomRoleSpawnChances.TryGetValue(role, out var valueRoleOpt) ? valueRoleOpt.GetChance() : 0; + bool roleDisabled = chancePerGame == 0; + + if (enabledOrNotCollapsed && role is not CustomRoles.Seeker and not CustomRoles.Hider) + { + if (OnlyEnabledRoles && roleDisabled) continue; + + ViewSettingsInfoPanelRoleVariant viewSettingsInfoPanelRoleVariant = Object.Instantiate(viewSettings.infoPanelRoleOrigin, viewSettings.settingsContainer); + viewSettingsInfoPanelRoleVariant.name = realName; + + // Max count title + var settingTitle = Object.Instantiate(viewSettingsInfoPanelRoleVariant.chanceTitle, viewSettingsInfoPanelRoleVariant.transform); + settingTitle.name = "MaxCountTitle"; + settingTitle.DestroyTranslator(); + settingTitle.text = Translator.GetString("Maximum"); + settingTitle.transform.localPosition = new(3.04f, -0.02f, -2f); + settingTitle.alignment = TextAlignmentOptions.Left; + settingTitle.enableWordWrapping = false; + settingTitle.overflowMode = TextOverflowModes.Overflow; + + // if start y pos not changed + if (yPos == 1.3f) yPos -= 0.8f; + viewSettingsInfoPanelRoleVariant.transform.localScale = Vector3.one; + viewSettingsInfoPanelRoleVariant.transform.localPosition = new Vector3(xPos, yPos, -2f); + + if (role.ToString().Contains("GuardianAngel")) role = CustomRoles.GA; + + titleName = titleName.RemoveHtmlTags(); + + switch (Options.UsePets.GetBool()) + { + case true when role.PetActivatedAbility(): + titleName += Translator.GetString("SupportsPetIndicator"); + break; + case false when role.OnlySpawnsWithPets(): + titleName += Translator.GetString("RequiresPetIndicator"); + break; + } + + if (role.IsExperimental()) titleName += $"{Translator.GetString("ExperimentalRoleIndicator")}"; + if (role.IsGhostRole()) titleName += StringOptionPatch.GetGhostRoleTeam(role); + if (role.IsDevFavoriteRole()) titleName += " <#00ffff>★"; + + var chanceAddOnPerGame = Options.CustomAdtRoleSpawnRate.TryGetValue(role, out var valueAddOnOpt) ? valueAddOnOpt.GetInt() : 0; + int numPerGame = Options.CustomRoleCounts.TryGetValue(role, out var valueInt) ? valueInt.GetInt() : 0; + + viewSettingsInfoPanelRoleVariant.SetInfo(titleName, numPerGame, chancePerGame, 61, option.NameColor, RoleManager.Instance.AllRoles[0].RoleIconSolid /*<- Role Icons sets here*/, tabName is not TabGroup.ImpostorRoles, roleDisabled); + + if (roleDisabled) + { + if (role.IsAdditionRole()) + { + //viewSettingsInfoPanelRoleVariant.chanceText.text = $"{Translator.GetString("RoleOff")}/{chanceAddOnPerGame}"; + viewSettingsInfoPanelRoleVariant.chanceText.text = Translator.GetString("RoleOff"); + viewSettingsInfoPanelRoleVariant.chanceText.outlineWidth = Translator.LangHasSensitiveOutlineText() ? 0.09f : 0.26f; + } + + viewSettingsInfoPanelRoleVariant.chanceBackground.color = Palette.DisabledGrey; + viewSettingsInfoPanelRoleVariant.background.color = Palette.DisabledGrey; + } + else + { + if (role.IsAdditionRole()) + { + viewSettingsInfoPanelRoleVariant.chanceText.text = $"{Translator.GetString("RoleRate")}/{chanceAddOnPerGame}"; + viewSettingsInfoPanelRoleVariant.chanceText.outlineWidth = Translator.LangHasSensitiveOutlineText() ? 0.09f : 0.26f; + } + + viewSettingsInfoPanelRoleVariant.chanceBackground.color = option.NameColor; + viewSettingsInfoPanelRoleVariant.background.color = option.NameColor; + RoleEnabledList.Add(role); + } + viewSettings.settingsInfo.Add(viewSettingsInfoPanelRoleVariant.gameObject); + yPos -= 0.65f; + } + else if (LastGameModeSelected == CustomGameMode.HideAndSeek && role is CustomRoles.Seeker or CustomRoles.Hider) + { + RoleEnabledList.Add(role); + } + else if (!enabledOrNotCollapsed && enabled && !roleDisabled) + { + RoleEnabledList.Add(role); + } + } + catch (Exception e) { Utils.ThrowException(e); } + } + viewSettings.scrollBar.SetYBoundsMax(-yPos - 4f); + } + + if (RoleEnabledList.Count <= 0) yield break; + yield return CoShowRoleSettings().WrapToIl2Cpp(); + + IEnumerator CoShowRoleSettings() + { + yPos -= 0.8f; + CategoryHeaderMasked categoryHeaderMasked2 = Object.Instantiate(viewSettings.categoryHeaderOrigin, viewSettings.settingsContainer); + categoryHeaderMasked2.SetHeader(StringNames.RoleSettingsLabel, 61); + categoryHeaderMasked2.transform.localScale = Vector3.one; + categoryHeaderMasked2.transform.localPosition = new Vector3(-9.77f, yPos, -2f); + viewSettings.settingsInfo.Add(categoryHeaderMasked2.gameObject); + + yPos -= 2.1f; + float startY = yPos; + + float leftY = startY; + float rightY = startY; + float leftX = -5.8f; + float rightX = 0.15f; + + foreach (var role in RoleEnabledList) + { + OptionItem optionRole = Options.CustomRoleSpawnChances.GetValueOrDefault(role); + if (optionRole == null || optionRole == default) + { + if (role == CustomRoles.Seeker) optionRole = OptionItem.FastOptions[Seeker.StartId]; + else if (role == CustomRoles.Hider) optionRole = OptionItem.FastOptions[Hider.StartId]; + else continue; + } + // 1 child setting is "Max" or "Spawn chance" setting + else if (optionRole.Children.Count <= 1) continue; + + bool useLeftColumn = leftY >= rightY; + float columnX = useLeftColumn ? leftX : rightX; + float columnY = useLeftColumn ? leftY : rightY; + + float endY = SetUpCustomRoleSettings(viewSettings, role, optionRole, tabName, 0.8f, 61, columnX, columnY); + + if (useLeftColumn) leftY = endY - 1.2f; + else rightY = endY - 1.2f; + + float currectLowestY = Mathf.Min(leftY, rightY); + viewSettings.scrollBar.SetYBoundsMax(-currectLowestY - 6f); + yield return null; + } + float endLowestY = Mathf.Min(leftY, rightY); + viewSettings.scrollBar.SetYBoundsMax(-endLowestY - 6f); + } + } + } + private static float SetUpCustomRoleSettings(this LobbyViewSettingsPane viewSettings, CustomRoles role, OptionItem optionRole, TabGroup tabName, float spacingY, int maskLayer, float xPosRoleHeader, float startY) + { + float yPos = startY; + BaseGameSetting data; + + AdvancedRoleViewPanel advancedRoleViewPanel = Object.Instantiate(viewSettings.advancedRolePanelOrigin, viewSettings.settingsContainer); + advancedRoleViewPanel.name = role + "AdvancedPanel"; + advancedRoleViewPanel.transform.localScale = Vector3.one; + advancedRoleViewPanel.transform.localPosition = new Vector3(xPosRoleHeader, yPos, -2f); + advancedRoleViewPanel.header.SetHeader((StringNames)(6000 + role), maskLayer, tabName is not TabGroup.ImpostorRoles, null /*<- Role Icons sets here*/); + advancedRoleViewPanel.divider.material.SetInt(PlayerMaterial.MaskLayer, maskLayer); + advancedRoleViewPanel.header.Title.text = Translator.GetString(role.ToString()); + advancedRoleViewPanel.header.Title.color = Color.white; + // default color + if (optionRole.NameColor != Color.white) + { + advancedRoleViewPanel.header.Background.color = optionRole.NameColor; + advancedRoleViewPanel.header.Divider.color = optionRole.NameColor; + } + else + { + var tabColor = tabName.GetTabColor(); + advancedRoleViewPanel.header.Background.color = tabColor; + advancedRoleViewPanel.header.Divider.color = tabColor; + } + viewSettings.settingsInfo.Add(advancedRoleViewPanel.gameObject); + + foreach (OptionItem firstOption in optionRole.Children) + { + bool show = firstOption.Name != "Maximum"; + if (!show) continue; + + data = GameOptionsMenuPatch.GetSetting(firstOption); + if (data == null) continue; + + DrawSetting(firstOption, data); + yPos -= spacingY; + + foreach (var secondOption in firstOption.Children) + { + data = GameOptionsMenuPatch.GetSetting(secondOption); + if (data == null) continue; + + DrawSetting(secondOption, data); + yPos -= spacingY; + + foreach (var thirdOption in secondOption.Children) + { + data = GameOptionsMenuPatch.GetSetting(thirdOption); + if (data == null) continue; + + DrawSetting(thirdOption, data); + yPos -= spacingY; + } + } + } + + if (yPos == startY) + advancedRoleViewPanel.gameObject.SetActive(false); + + void DrawSetting(OptionItem option, BaseGameSetting data) + { + ViewSettingsInfoPanel viewSettingsInfoPanel = Object.Instantiate(advancedRoleViewPanel.infoPanelOrigin, advancedRoleViewPanel.transform.parent, true); + viewSettingsInfoPanel.name = option.Name; + viewSettingsInfoPanel.transform.localScale = Vector3.one; + viewSettingsInfoPanel.transform.localPosition = new Vector3(xPosRoleHeader - 3f, yPos, -2f); + + switch (data.Type) + { + case OptionTypes.Checkbox: + viewSettingsInfoPanel.SetInfoCheckbox(data.Title, 61, option.GetBool()); + Color32 color = LastGameModeSelected == CustomGameMode.Standard ? tabName switch + { + TabGroup.ImpostorRoles => new Color32(255, 25, 25, 255), + TabGroup.CrewmateRoles => new Color32(140, 255, 255, 255), + TabGroup.NeutralRoles => new Color32(255, 171, 27, 255), + TabGroup.CovenRoles => new Color32(123, 63, 187, 255), + _ => new Color32(0, 165, 255, 255) + } : Main.GameModeColors.TryGetValue(LastGameModeSelected, out var c) ? c : new Color32(0, 165, 255, 255); + viewSettingsInfoPanel.checkMark.color = color; + break; + case OptionTypes.String: + viewSettingsInfoPanel.SetInfo(data.Title, option.GetString(), 61); + break; + case OptionTypes.Float: + viewSettingsInfoPanel.SetInfo(data.Title, data.GetValueString(option.GetFloat()), 61); + break; + case OptionTypes.Int: + viewSettingsInfoPanel.SetInfo(data.Title, data.GetValueString(option.GetInt()), 61); + break; + default: + viewSettingsInfoPanel.SetInfo(data.Title, option.GetString(), 61); + break; + } + viewSettingsInfoPanel.titleText.text = option.GetName(); + + Color labelColor = new(0.6f, 0.6f, 0.6f); + if (option.Parent?.Parent?.Parent != null) labelColor = new(0.6f, 0.6f, 0f); + else if (option.Parent?.Parent != null) labelColor = new(0f, 0f, 0.6f); + + viewSettingsInfoPanel.labelBackground.color = labelColor; + viewSettings.settingsInfo.Add(viewSettingsInfoPanel.gameObject); + } + return yPos; + } + private static bool AllParentsEnabledAndVisible(OptionItem o, bool checkCollapsedSection = true) + { + while (true) + { + if (o == null) return true; + if (o.IsCurrentlyHidden(forLobbyView: true, checkCollapsedSection: checkCollapsedSection) || !o.GetBool()) return false; + o = o.Parent; + } + } +} diff --git a/Patches/PlayerJoinAndLeftPatch.cs b/Patches/PlayerJoinAndLeftPatch.cs index 7ed4387e4..a5b15e196 100644 --- a/Patches/PlayerJoinAndLeftPatch.cs +++ b/Patches/PlayerJoinAndLeftPatch.cs @@ -96,7 +96,7 @@ internal static class OnGameJoinedPatch ClientData client = PlayerControl.LocalPlayer.GetClient(); Logger.Info($"{client.PlayerName.RemoveHtmlTags()} (ClientID: {client.Id} / FriendCode: {client.FriendCode} / HashPuid: {client.GetHashedPuid()} / Platform: {client.PlatformData.Platform}) Hosted room (Server: {Utils.GetRegionName()})", "Session"); - Main.Instance.StartCoroutine(OptionShower.GetText()); + //Main.Instance.StartCoroutine(OptionShower.GetText()); }, 1f, "OnGameJoinedPatch"); LateTask.New(() => @@ -244,8 +244,8 @@ internal static class OnGameJoinedPatch } } } - else - LateTask.New(() => Main.Instance.StartCoroutine(OptionShower.GetText()), 10f, "OptionShower.GetText on client"); + //else + // LateTask.New(() => Main.Instance.StartCoroutine(OptionShower.GetText()), 10f, "OptionShower.GetText on client"); } // Written with AI because I don't want it to delete the wrong files diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs index 781519139..48bc1afca 100644 --- a/Patches/ShipStatusPatch.cs +++ b/Patches/ShipStatusPatch.cs @@ -9,6 +9,9 @@ using EHR.Roles; using HarmonyLib; using Hazel; using UnityEngine; +#if DEBUG +using EHR.Patches; +#endif namespace EHR; diff --git a/README.md b/README.md index 76e990dd4..08c95be1c 100644 --- a/README.md +++ b/README.md @@ -537,6 +537,12 @@ Click this badge to view our translation project: > > - Crowded is integrated into EHR + +### :star: [MiraAPI](https://github.com/All-Of-Us-Mods/MiraAPI) + +> +> - Next button sprites (Inactive and Active) + ### Endless Host Roles (EHR), with Endless Possibilities, brought to you by the Endless Network. diff --git a/Resources/Images/ActiveNextButton.png b/Resources/Images/ActiveNextButton.png new file mode 100644 index 000000000..62ac434e6 Binary files /dev/null and b/Resources/Images/ActiveNextButton.png differ diff --git a/Resources/Images/CheckMarkOff.png b/Resources/Images/CheckMarkOff.png new file mode 100644 index 000000000..fc34b0a3d Binary files /dev/null and b/Resources/Images/CheckMarkOff.png differ diff --git a/Resources/Images/DefaultPlate.png b/Resources/Images/DefaultPlate.png new file mode 100644 index 000000000..f770893ec Binary files /dev/null and b/Resources/Images/DefaultPlate.png differ diff --git a/Resources/Images/InactiveNextButton.png b/Resources/Images/InactiveNextButton.png new file mode 100644 index 000000000..0eea8eabf Binary files /dev/null and b/Resources/Images/InactiveNextButton.png differ diff --git a/Resources/Lang/en_US.jsonc b/Resources/Lang/en_US.jsonc index 2f5c8b92b..9b68d2f7e 100644 --- a/Resources/Lang/en_US.jsonc +++ b/Resources/Lang/en_US.jsonc @@ -10155,6 +10155,12 @@ "MainMenu.ExitGameButton": "Quit", "MainMenu.InventoryButton": "Inventory", + /* ============================== + Lobby View Settings + ============================== */ + "LobbyViewSettings_ShowOnlyEnabledRolesButtonText": "Show Only Enabled Roles", + "LobbyViewSettings_ShowAlldRolesButtonText": "Show All Roles", + /* ============================== General Settings ============================== */ @@ -11479,11 +11485,11 @@ "RoleSubCategoryLimitOptions.Neutral_Pariah.EnableLimit": "<#ffffff>Alter the number of Neutral Pariah <#ffffff>roles in the game", "RoleSubCategoryLimitOptions.Neutral_Pariah.Max": "Maximum Neutral Pariah Roles", "RoleSubCategoryLimitOptions.Neutral_Pariah.Min": "Minimum Neutral Pariah Roles", - + /* ============================== Faction Information ============================== */ - + "CovenInfoDescription": "The Coven is a Team of 1-4 people, after 3 meetings (amount replaced with hosts settings) a random Member of the Coven will gain the Necronomicon. With the Necronomicon, that Coven Member may kill normally and also has a stronger ability. After the Necronomicon was given to the first member, every meeting after will give it to another until all members of the Coven have it. Most roles in this faction are also Support oriented, meaning that they need Teamwork and coordination to work perfectly together.\n\nThe Necronomicon is an ability buff owned by a single member of the Coven. The Necronomicon goes to a different Coven member after every meeting, and for that round will buff their role's ability. Most Coven roles will state in their description what the Necronomicon buffs in their role.\n\nCredit to mystic_haze2 on Discord for writing the first paragraph", "NeutralInfoDescription": "Neutrals do not belong to Crewmates or Impostors, and they win on their own terms. Each type of neutral wins in a different way. Neutrals work for themselves and have specific conditions depending on their role on how to win.\n\nNeutral Benigns win when their specific conditions are completed, each role having different conditions necessary to win. They do not trigger the game to end, meaning they must wait until the Crewmates, Impostors, Coven, or another Neutral to win the game and win along with them. \n\nNeutral Evils also have their own specific conditions to win, much like the Neutral Benigns. However, when they complete their objectives to win the game, they end the game and win without Crewmates, Coven, or Impostors- also called 'stealing the win'.\n\nNeutral Killers are neutrals who can kill, much like Impostors, but do not work with the Impostors. Most of the Neutral killers work on their own, although some can recruit other players to work with them. They win the game by killing off all the Impostors, Cremwates, Coven, and other Neutrals, until they are the only player remaining.\n\nNeutral Pariah roles are much like Neutral Benign roles, however their main objective is to make sure Crewmates do not win. If any team other than the Crewmates win, said Neutral Pariah role will win along with the winning team. They have special abilities to try and harm the crewmates." } diff --git a/Roles/HideAndSeek/Agent.cs b/Roles/HideAndSeek/Agent.cs index 3f2449856..a061278e3 100644 --- a/Roles/HideAndSeek/Agent.cs +++ b/Roles/HideAndSeek/Agent.cs @@ -16,6 +16,10 @@ public class Agent : RoleBase, IHideAndSeekRole public override void SetupCustomOption() { + new TextOptionItem(69_211_2000, $"TypeImpostor", TabGroup.ImpostorRoles) + .SetHeader(true) + .SetGameMode(CustomGameMode.HideAndSeek); + Options.SetupRoleOptions(69_211_2001, TabGroup.ImpostorRoles, CustomRoles.Agent, CustomGameMode.HideAndSeek); Vision = new FloatOptionItem(69_211_2003, "AgentVision", new(0.05f, 5f, 0.05f), 0.25f, TabGroup.ImpostorRoles) diff --git a/Roles/HideAndSeek/Detector.cs b/Roles/HideAndSeek/Detector.cs index 3cda9c4ed..ee4db7d07 100644 --- a/Roles/HideAndSeek/Detector.cs +++ b/Roles/HideAndSeek/Detector.cs @@ -21,6 +21,10 @@ public class Detector : RoleBase, IHideAndSeekRole public override void SetupCustomOption() { + new TextOptionItem(69_211_600, $"TypeCrewmate", TabGroup.CrewmateRoles) + .SetHeader(true) + .SetGameMode(CustomGameMode.HideAndSeek); + Options.SetupRoleOptions(69_211_601, TabGroup.CrewmateRoles, CustomRoles.Detector, CustomGameMode.HideAndSeek); Vision = new FloatOptionItem(69_211_603, "DetectorVision", new(0.05f, 5f, 0.05f), 1.25f, TabGroup.CrewmateRoles) diff --git a/Roles/HideAndSeek/Fox.cs b/Roles/HideAndSeek/Fox.cs index c198cf0e8..54c9a2d7f 100644 --- a/Roles/HideAndSeek/Fox.cs +++ b/Roles/HideAndSeek/Fox.cs @@ -16,6 +16,10 @@ internal class Fox : RoleBase, IHideAndSeekRole public override void SetupCustomOption() { + new TextOptionItem(69_211_300, $"TypeNeutral", TabGroup.NeutralRoles) + .SetHeader(true) + .SetGameMode(CustomGameMode.HideAndSeek); ; + Options.SetupRoleOptions(69_211_301, TabGroup.NeutralRoles, CustomRoles.Fox, CustomGameMode.HideAndSeek); Vision = new FloatOptionItem(69_211_303, "FoxVision", new(0.05f, 5f, 0.05f), 1.25f, TabGroup.NeutralRoles) diff --git a/Roles/HideAndSeek/Hider.cs b/Roles/HideAndSeek/Hider.cs index ddb9bd0a6..faff27349 100644 --- a/Roles/HideAndSeek/Hider.cs +++ b/Roles/HideAndSeek/Hider.cs @@ -6,6 +6,8 @@ internal class Hider : RoleBase, IHideAndSeekRole { private static bool On; + public static int StartId = 69_211_199; + private static OptionItem Vision; private static OptionItem Speed; private static OptionItem TimeDecreaseOnShortTaskComplete; @@ -23,45 +25,53 @@ internal class Hider : RoleBase, IHideAndSeekRole public override void SetupCustomOption() { - new TextOptionItem(69_211_199, "Hider", TabGroup.CrewmateRoles) + var textOpt = new TextOptionItem(StartId, "Hider", TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) - .SetHeader(true) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetHeader(true); + + textOpt.SetValue(1, false, false); // Set Value as 1, becouse TextOptionItem "Hider" is parent option Vision = new FloatOptionItem(69_211_101, "HiderVision", new(0.05f, 5f, 0.05f), 1.25f, TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Multiplier) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetColor(new(52, 94, 235, byte.MaxValue)) + .SetParent(textOpt); Speed = new FloatOptionItem(69_211_102, "HiderSpeed", new(0.05f, 5f, 0.05f), 1.4f, TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Multiplier) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetColor(new(52, 94, 235, byte.MaxValue)) + .SetParent(textOpt); TimeDecreaseOnShortTaskComplete = new IntegerOptionItem(69_211_103, "TimeDecreaseOnShortTaskComplete", new(0, 60, 1), 5, TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Seconds) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetColor(new(52, 94, 235, byte.MaxValue)) + .SetParent(textOpt); TimeDecreaseOnCommonTaskComplete = new IntegerOptionItem(69_211_104, "TimeDecreaseOnCommonTaskComplete", new(0, 60, 1), 10, TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Seconds) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetColor(new(52, 94, 235, byte.MaxValue)) + .SetParent(textOpt); TimeDecreaseOnLongTaskComplete = new IntegerOptionItem(69_211_105, "TimeDecreaseOnLongTaskComplete", new(0, 60, 1), 15, TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Seconds) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetColor(new(52, 94, 235, byte.MaxValue)) + .SetParent(textOpt); TimeDecreaseOnSituationalTaskComplete = new IntegerOptionItem(69_211_106, "TimeDecreaseOnSituationalTaskComplete", new(0, 60, 1), 20, TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Seconds) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetColor(new(52, 94, 235, byte.MaxValue)) + .SetParent(textOpt); TimeDecreaseOnOtherTaskComplete = new IntegerOptionItem(69_211_107, "TimeDecreaseOnOtherTaskComplete", new(0, 60, 1), 5, TabGroup.CrewmateRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Seconds) - .SetColor(new(52, 94, 235, byte.MaxValue)); + .SetColor(new(52, 94, 235, byte.MaxValue)) + .SetParent(textOpt); } public override void Add(byte playerId) diff --git a/Roles/HideAndSeek/Seeker.cs b/Roles/HideAndSeek/Seeker.cs index e5c071dad..dac995c2b 100644 --- a/Roles/HideAndSeek/Seeker.cs +++ b/Roles/HideAndSeek/Seeker.cs @@ -6,6 +6,8 @@ internal class Seeker : RoleBase, IHideAndSeekRole { public static bool On; + public static int StartId = 69_211_299; + public static OptionItem Vision; public static OptionItem Speed; public static OptionItem CanVent; @@ -21,34 +23,40 @@ internal class Seeker : RoleBase, IHideAndSeekRole public override void SetupCustomOption() { - new TextOptionItem(69_211_299, "Seeker", TabGroup.ImpostorRoles) + var textOpt = new TextOptionItem(StartId, "Seeker", TabGroup.ImpostorRoles) .SetGameMode(CustomGameMode.HideAndSeek) - .SetHeader(true) - .SetColor(new(255, 25, 25, byte.MaxValue)); + .SetHeader(true); + + textOpt.SetValue(1, false, false); // Set Value as 1, becouse TextOptionItem "Seeker" is parent option Vision = new FloatOptionItem(69_211_201, "SeekerVision", new(0.05f, 5f, 0.05f), 0.25f, TabGroup.ImpostorRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Multiplier) - .SetColor(new(255, 25, 25, byte.MaxValue)); + .SetColor(new(255, 25, 25, byte.MaxValue)) + .SetParent(textOpt); Speed = new FloatOptionItem(69_211_202, "SeekerSpeed", new(0.05f, 5f, 0.05f), 1.5f, TabGroup.ImpostorRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Multiplier) - .SetColor(new(255, 25, 25, byte.MaxValue)); + .SetColor(new(255, 25, 25, byte.MaxValue)) + .SetParent(textOpt); CanVent = new BooleanOptionItem(69_211_204, "CanVent", false, TabGroup.ImpostorRoles) .SetGameMode(CustomGameMode.HideAndSeek) - .SetColor(new(255, 25, 25, byte.MaxValue)); + .SetColor(new(255, 25, 25, byte.MaxValue)) + .SetParent(textOpt); BlindTime = new FloatOptionItem(69_211_206, "BlindTime", new(0f, 60f, 1f), 10f, TabGroup.ImpostorRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Seconds) - .SetColor(new(255, 25, 25, byte.MaxValue)); + .SetColor(new(255, 25, 25, byte.MaxValue)) + .SetParent(textOpt); KillCooldown = new IntegerOptionItem(69_211_207, "KillCooldown", new(0, 60, 1), 10, TabGroup.ImpostorRoles) .SetGameMode(CustomGameMode.HideAndSeek) .SetValueFormat(OptionFormat.Seconds) - .SetColor(new(255, 25, 25, byte.MaxValue)); + .SetColor(new(255, 25, 25, byte.MaxValue)) + .SetParent(textOpt); } public override void Add(byte playerId)