diff --git a/MiraAPI/Patches/RoleGuidePatches.cs b/MiraAPI/Patches/RoleGuidePatches.cs index 2395d5f..54df050 100644 --- a/MiraAPI/Patches/RoleGuidePatches.cs +++ b/MiraAPI/Patches/RoleGuidePatches.cs @@ -7,7 +7,11 @@ using HarmonyLib; using Innersloth.Assets; using MiraAPI.Roles; using MiraAPI.Utilities; +using Reactor.Utilities.Extensions; +using TMPro; using UnityEngine; +using UnityEngine.Events; +using UnityEngine.UI; using Object = UnityEngine.Object; namespace MiraAPI.Patches; @@ -39,6 +43,8 @@ public static class RoleGuidePatches __instance.MatchInfoRoleMaskArea.transform.parent.GetAllChildren() .First(x => x.name.Contains("BG_Gradient")).GetComponent() .maskInteraction = SpriteMaskInteraction.VisibleInsideMask; + var wikiTab = Object.Instantiate(__instance.settingsTabs[2], __instance.settingsTabs[2].transform.parent); + advancedWikiTab = wikiTab.GetComponent(); } [HarmonyPrefix] @@ -78,13 +84,26 @@ public static class RoleGuidePatches var enabled = ActiveInputManager.currentControlType == ActiveInputManager.InputType.Joystick; __instance.glyphL.enabled = enabled; __instance.glyphR.enabled = enabled; + if (!titleText) + { + titleText = __instance.transitionOpen.transform.FindChild("Text_Title")?.GetComponent()!; + if (titleText) + { + titleText.transform.GetComponent().Destroy(); + } + } + + if (titleText) + { + titleText.text = TranslationController.Instance.GetString(StringNames.MatchInfoGuideTitle); + } + if (GameManager.Instance.TryCast() != null) { if (__instance.NormalModeSettings.Count == 0) { __instance.numOfTabs = 3; __instance.TabButtons[0].SelectButton(true); - DisplayNormalRoleSettings(__instance, true); __instance.MatchInfoRoleMaskArea.transform.localPosition = new Vector3(-0.0184f, 0.15f, -0.1f); __instance.matchInfoPlayersMaskArea.transform.localPosition = @@ -103,6 +122,12 @@ public static class RoleGuidePatches __instance.MatchInfoRoleMaskArea.transform.parent.GetAllChildren() .First(x => x.name.Contains("BG_Gradient")).GetComponent() .maskInteraction = SpriteMaskInteraction.VisibleInsideMask; + __instance.MatchInfoRoleMaskArea.material.SetInt(PlayerMaterial.MaskLayer, 50); + __instance.matchInfoSettingsMaskArea.material.SetInt(PlayerMaterial.MaskLayer, 50); + var wikiTab = Object.Instantiate(__instance.settingsTabs[2], __instance.settingsTabs[2].transform.parent); + wikiTab.transform.FindChild("MaskArea")?.transform.localPosition = new Vector3(-0.0184f, 0.15f, -0.1f); + advancedWikiTab = wikiTab.GetComponent(); + DisplayNormalRoleSettings(__instance, true); } else { @@ -130,6 +155,9 @@ public static class RoleGuidePatches } private static readonly Dictionary RolePanels = []; + private static Scroller advancedWikiTab; + private static GameObject currentAdvancedTabObject; + private static TextMeshPro titleText; public static void DisplayNormalRoleSettings(MatchInfoGuide instance, bool reset) { @@ -160,6 +188,8 @@ public static class RoleGuidePatches instance.CreateSettingsEntry( StringNames.GameTaskBarMode, GameManager.Instance.LogicOptions.GetTaskBarMode().ToString()); + + var hoverColor = new Color32(255, 255, 255, 150); foreach (var roleBehaviour in RoleManager.Instance.AllRoles) { if (roleBehaviour.Role is not RoleTypes.Crewmate and not RoleTypes.Impostor and @@ -169,11 +199,33 @@ public static class RoleGuidePatches var panel = Object.Instantiate( instance.MatchInfoRolePanelPrefab, instance.settingsTabs[2].GetComponent().Inner); + var collider = panel.roleIcon.gameObject.AddComponent(); + collider.size = new Vector2(0.13f, 0.13f); + collider.offset = new Vector2(0, 0); + var passiveButton = panel.roleIcon.gameObject.AddComponent(); + passiveButton.OnMouseOver = new UnityEvent(); + passiveButton.OnMouseOver.AddListener( + (UnityAction)(() => + { + panel.roleIcon.color = hoverColor; + })); + passiveButton.OnMouseOut = new UnityEvent(); + passiveButton.OnMouseOut.AddListener( + (UnityAction)(() => + { + panel.roleIcon.color = Color.white; + })); + + passiveButton.OnClick = new Button.ButtonClickedEvent(); + passiveButton.OnClick.AddListener( + (Action)(() => { DisplayAdvancedWiki(instance, roleBehaviour); })); RolePanels.Add(roleBehaviour, panel); } } } + advancedWikiTab?.gameObject.SetActive(false); + var num = 0; foreach (var (roleData, panel) in RolePanels) { @@ -202,8 +254,7 @@ public static class RoleGuidePatches } instance.MatchInfoRoleScroller.SetYBoundsMax(Mathf.Clamp(Mathf.Ceil(num / 2f) * 1.3f - 1.5f, 0f, 999f)); - instance.MatchInfoRoleMaskArea.material.SetInt(PlayerMaterial.MaskLayer, 50); - instance.matchInfoSettingsMaskArea.material.SetInt(PlayerMaterial.MaskLayer, 50); + instance.MatchInfoRoleScroller.SetYBoundsMax(Mathf.Clamp(Mathf.Ceil(num / 2f) * 1.3f - 1.5f, 0f, 999f)); if (reset) { instance.CreatePlayerEntries(); @@ -234,9 +285,6 @@ public static class RoleGuidePatches __instance.CoLoadAssetAsync( namePlate.GetAssetReference(), (Action?)LoadNameplate)); -#pragma warning disable S1751 // Loops with at most one iteration should be refactored (Justification: No idea why it's behaving this way.) - continue; -#pragma warning restore S1751 // Loops with at most one iteration should be refactored void LoadNameplate(NamePlateViewData viewData) { @@ -249,6 +297,67 @@ public static class RoleGuidePatches return false; } + [HarmonyPostfix] + [HarmonyPriority(Priority.First)] + [HarmonyPatch(typeof(MatchInfoGuide), nameof(MatchInfoGuide.SetActiveTab))] + private static void SetActiveTab() + { + if (titleText) + { + titleText.text = TranslationController.Instance.GetString(StringNames.MatchInfoGuideTitle); + } + + advancedWikiTab?.gameObject.SetActive(false); + } + + public static void DisplayAdvancedWiki(MatchInfoGuide instance, RoleBehaviour role) + { + Warning($"Opening advanced tab for {role.GetRoleName()}."); + instance.settingsTabs[2].SetActive(false); + advancedWikiTab?.gameObject.SetActive(true); + if (currentAdvancedTabObject) + { + currentAdvancedTabObject.SetActive(false); + currentAdvancedTabObject.Destroy(); + } + + if (advancedWikiTab == null) + { + Warning($"Wiki tab is null."); + return; + } + + if (role is ICustomRole custom) + { + currentAdvancedTabObject = custom.GetAdvancedWiki(instance, titleText, advancedWikiTab); + currentAdvancedTabObject.transform.localPosition = new Vector3(0f, 0f, 0f); + } + else + { + advancedWikiTab.ScrollToTop(); + currentAdvancedTabObject = new GameObject($"{role.Role}"); + titleText.text = role.GetRoleName() + $" ({TranslationController.Instance.GetString(role.TeamType is RoleTeamTypes.Crewmate ? StringNames.Crewmate : StringNames.Impostor)})"; + var desc = Object.Instantiate(instance.MatchInfoRolePanelPrefab.roleCount, currentAdvancedTabObject.transform); + desc.fontSizeMin = desc.fontSizeMax = desc.fontSize = 2f; + var description = TranslationController.Instance.GetString(role.BlurbNameLong); + if (description.Contains("STRMISS")) + { + var baseName = $"{role.StringName}".Replace("Role", string.Empty); + if (Enum.TryParse($"RolesHelp_{baseName}_01", out var helpName)) + { + description = TranslationController.Instance.GetString(helpName); + } + } + + desc.text = description; + desc.rectTransform.sizeDelta = new Vector2(7.5f, 0.3f); + desc.alignment = TextAlignmentOptions.TopLeft; + currentAdvancedTabObject.transform.SetParent(advancedWikiTab.Inner.transform); + desc.transform.localPosition = new Vector3(0, 1.125f, 0); + currentAdvancedTabObject.transform.localPosition = new Vector3(0f, 0f, 0f); + } + } + [HarmonyPrefix] [HarmonyPriority(Priority.First)] [HarmonyPatch(typeof(MatchInfoRolePanel), nameof(MatchInfoRolePanel.SetPanel))] diff --git a/MiraAPI/Roles/ICustomRole.cs b/MiraAPI/Roles/ICustomRole.cs index 403b414..817b209 100644 --- a/MiraAPI/Roles/ICustomRole.cs +++ b/MiraAPI/Roles/ICustomRole.cs @@ -6,7 +6,9 @@ using MiraAPI.GameOptions; using MiraAPI.Modifiers; using MiraAPI.PluginLoading; using MiraAPI.Translation; +using TMPro; using UnityEngine; +using Object = UnityEngine.Object; namespace MiraAPI.Roles; @@ -68,7 +70,7 @@ public interface ICustomRole : IOptionable /// /// Gets the wiki description of the role. Used in the wiki, but not currently required. /// - string RoleWikiDescription => MiraLocaleManager.Get(RoleLongDescriptionLocale); + string RoleWikiDescription => MiraLocaleManager.Get(RoleWikiDescriptionLocale, RoleLongDescription); /// /// Gets the role's wiki description id for localization. @@ -307,6 +309,28 @@ public interface ICustomRole : IOptionable /// if the role is always displayed, otherwise if it is never displayable, or if it is dictated by amount and chance. bool? ForceShowRoleOnWiki => null; + /// + /// Gets the information to display in the wiki. + /// + /// The guide object. + /// The title text object. + /// The scroller parent. + /// The of the wiki. + GameObject GetAdvancedWiki(MatchInfoGuide guide, TextMeshPro titleText, Scroller parent) + { + parent.ScrollToTop(); + var obj = new GameObject(RoleNameLocale); + titleText.text = RoleName + $" ({RoleFactionTitle})"; + var desc = Object.Instantiate(guide.MatchInfoRolePanelPrefab.roleCount, obj.transform); + desc.fontSizeMin = desc.fontSizeMax = desc.fontSize = 2f; + desc.text = RoleWikiDescription; + desc.rectTransform.sizeDelta = new Vector2(7.5f, 0.3f); + desc.alignment = TextAlignmentOptions.TopLeft; + obj.transform.SetParent(parent.Inner.transform); + desc.transform.localPosition = new Vector3(0, 1.125f, 0); + return obj; + } + /// /// Gets the function that determines whether the role should be toggled on or off in the game settings. ///