]> git.deb.at Git - rhonda/theotherroles.git/commitdiff
Update v4.6.0
authorgendelo3 <gendelo3@gmail.com>
Thu, 1 Aug 2024 10:19:33 +0000 (12:19 +0200)
committergendelo3 <gendelo3@gmail.com>
Thu, 1 Aug 2024 10:19:33 +0000 (12:19 +0200)
47 files changed:
README.md
TheOtherRoles.sln
TheOtherRoles/Buttons.cs
TheOtherRoles/CustomGameModes/GameModePatches.cs [new file with mode: 0644]
TheOtherRoles/CustomGameModes/PropHunt.cs
TheOtherRoles/CustomOptionHolder.cs
TheOtherRoles/Helpers.cs
TheOtherRoles/Main.cs
TheOtherRoles/MapOptions.cs
TheOtherRoles/Modules/BepInExUpdater.cs
TheOtherRoles/Modules/ChatCommands.cs
TheOtherRoles/Modules/CustomColors.cs
TheOtherRoles/Modules/CustomHats/Patches/HatParentPatches.cs
TheOtherRoles/Modules/CustomHats/Patches/HatsTabPatches.cs
TheOtherRoles/Modules/CustomOptions.cs
TheOtherRoles/Objects/Footprint.cs
TheOtherRoles/Objects/Silhouette.cs
TheOtherRoles/Patches/ClientOptionsPatch.cs
TheOtherRoles/Patches/ConstantsPatch.cs
TheOtherRoles/Patches/CredentialsPatch.cs
TheOtherRoles/Patches/EndGamePatch.cs
TheOtherRoles/Patches/ExileControllerPatch.cs
TheOtherRoles/Patches/GameStartManagerPatch.cs
TheOtherRoles/Patches/GetStringPatch.cs [new file with mode: 0644]
TheOtherRoles/Patches/IntroPatch.cs
TheOtherRoles/Patches/MeetingPatch.cs
TheOtherRoles/Patches/PlayerControlPatch.cs
TheOtherRoles/Patches/RegionMenuPatch.cs
TheOtherRoles/Patches/RoleAssignmentPatch.cs
TheOtherRoles/Patches/ShipStatusPatch.cs
TheOtherRoles/Patches/UsablesPatch.cs
TheOtherRoles/Players/CachedPlayer.cs
TheOtherRoles/RPC.cs
TheOtherRoles/Resources/Copy.png [new file with mode: 0644]
TheOtherRoles/Resources/CopyActive.png [new file with mode: 0644]
TheOtherRoles/Resources/CopyPasteBG.png [new file with mode: 0644]
TheOtherRoles/Resources/Minus_Button.png [new file with mode: 0644]
TheOtherRoles/Resources/Minus_ButtonActive.png [new file with mode: 0644]
TheOtherRoles/Resources/Paste.png [new file with mode: 0644]
TheOtherRoles/Resources/PasteActive.png [new file with mode: 0644]
TheOtherRoles/Resources/Plus_Button.png [new file with mode: 0644]
TheOtherRoles/Resources/Plus_ButtonActive.png [new file with mode: 0644]
TheOtherRoles/Resources/Settings_Button.png [new file with mode: 0644]
TheOtherRoles/Resources/Settings_ButtonActive.png [new file with mode: 0644]
TheOtherRoles/TasksHandler.cs
TheOtherRoles/TheOtherRoles.csproj
TheOtherRoles/packages.lock.json

index 4e04661ad4ccfba715da6b906296f22c74f7770b..7ac7ef69f23ed4b59135e7a1f61779fea61ad99d 100644 (file)
--- a/README.md
+++ b/README.md
@@ -42,15 +42,16 @@ The [Role Assignment](#role-assignment) section explains how the roles are being
 # Releases
 | Among Us - Version| Mod Version | Link |
 |----------|-------------|-----------------|
+| 2024.6.18s| v4.6.0| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.6.0/TheOtherRoles.zip)
 | 2024.3.5s| v4.5.3| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.5.3/TheOtherRoles.zip)
-| 2024.3.5s| v4.5.2| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.5.2/TheOtherRoles.zip)
-| 2023.11.28s| v4.5.1| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.5.1/TheOtherRoles.zip)
 
 <details>
   <summary>Click to show older versions</summary>
   
 | Among Us - Version| Mod Version | Link |
 |----------|-------------|-----------------|
+| 2024.3.5s| v4.5.2| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.5.2/TheOtherRoles.zip)
+| 2023.11.28s| v4.5.1| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.5.1/TheOtherRoles.zip)
 | 2023.11.28s| v4.5.0| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.5.0/TheOtherRoles.zip)
 | 2023.07.12s| v4.4.2| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.4.2/TheOtherRoles.zip)
 | 2023.07.12s| v4.4.1| [Download](https://github.com/TheOtherRolesAU/TheOtherRoles/releases/download/v4.4.1/TheOtherRoles.zip)
@@ -133,6 +134,20 @@ The [Role Assignment](#role-assignment) section explains how the roles are being
 <details>
   <summary>Click to show the Changelog</summary>
   
+  
+** Version 4.6.0**
+- Updated to Among Us version 2024.6.18 (Vanilla Update with new UI elements and many Server Side Changes)
+- Added a completely new UI for the Mod's Options, using the new Vanilla Design.
+- Added a button to switch gamemodes in the lobby
+- Added an option to enable the Chat-Notification in game (in Mod Options)
+- Fixed a bug where the shielding the bomber would show a murder attempt on the bomber, when they plant a bomb (sorry Vlesk)
+- Fixed a bug in PropHunt, where the background of the Prop-Display was visible in the cameras
+- Fixed a bug where guessing a player would sometimes not return the votes to the voters
+- Fixed a bug where the Lawyer would not properly die when guessing the client
+- Removed: Disabled Vanilla Servers for now, as the mod is incompatible with them in its / their current state. Thanks to Miniduikboat for making custom servers great again!
+- Experimental: Advanded users can try to install the mod on the Windows Store Version of Among Us. No Support Provided!
+
+  
 **Version 4.5.3**
 - Added a new role: Yo-Yo (Impostor) - Mark and blink to a position, then blink back to the start of the blink!
 - Added a new option to Jackal And Sidekick: Jackal / Sidekick can sabotage lights (cooldown syncs with Imp Sabotages)
index 3c00efe92fc7b5a1ea80f1957acdcce663c56def..a61126ed981382535f4af810da276b486ad3fc25 100644 (file)
@@ -1,6 +1,9 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheOtherRoles", "TheOtherRoles\TheOtherRoles.csproj", "{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}"
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34728.123
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheOtherRoles", "TheOtherRoles\TheOtherRoles.csproj", "{11FBC798-BAF5-4EE5-9511-BE6DB0592F99}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TheOtherUpdater", "TheOtherUpdater\TheOtherUpdater.vcxproj", "{73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}"
 EndProject
@@ -19,4 +22,10 @@ Global
                {73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}.Release|Any CPU.ActiveCfg = Release|Win32
                {73A5662B-9C59-4C97-95C5-F5B2A8BBDDCA}.Release|Any CPU.Build.0 = Release|Win32
        EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {0CC3F51E-CC66-4122-B4CB-3A0B59DE563C}
+       EndGlobalSection
 EndGlobal
index 763bbda9838ab1499590d2fef4bba786a0ed42c3..7c56ec1c57e8e7ac6b559942fd9b27d21f4288f6 100644 (file)
@@ -277,7 +277,7 @@ namespace TheOtherRoles
             // Add poolable player to the button so that the target outfit is shown
             button.actionButton.cooldownTimerText.transform.localPosition = new Vector3(0, 0, -1f);  // Before the poolable player
             targetDisplay = UnityEngine.Object.Instantiate<PoolablePlayer>(Patches.IntroCutsceneOnDestroyPatch.playerPrefab, button.actionButton.transform);
-            GameData.PlayerInfo data = target.Data;
+            NetworkedPlayerInfo data = target.Data;
             target.SetPlayerMaterialColors(targetDisplay.cosmetics.currentBodySprite.BodySprite);
             targetDisplay.SetSkin(data.DefaultOutfit.SkinId, data.DefaultOutfit.ColorId);
             targetDisplay.SetHat(data.DefaultOutfit.HatId, data.DefaultOutfit.ColorId);
@@ -364,7 +364,7 @@ namespace TheOtherRoles
                                 Vector2 truePosition2 = component.TruePosition;
                                 if (Vector2.Distance(truePosition2, truePosition) <= CachedPlayer.LocalPlayer.PlayerControl.MaxReportDistance && CachedPlayer.LocalPlayer.PlayerControl.CanMove && !PhysicsHelpers.AnythingBetween(truePosition, truePosition2, Constants.ShipAndObjectsMask, false))
                                 {
-                                    GameData.PlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId);
+                                    NetworkedPlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId);
 
                                     MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.CleanBody, Hazel.SendOption.Reliable, -1);
                                     writer.Write(playerInfo.PlayerId);
@@ -1177,7 +1177,7 @@ namespace TheOtherRoles
                                 Vector2 truePosition2 = component.TruePosition;
                                 if (Vector2.Distance(truePosition2, truePosition) <= CachedPlayer.LocalPlayer.PlayerControl.MaxReportDistance && CachedPlayer.LocalPlayer.PlayerControl.CanMove && !PhysicsHelpers.AnythingBetween(truePosition, truePosition2, Constants.ShipAndObjectsMask, false))
                                 {
-                                    GameData.PlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId);
+                                    NetworkedPlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId);
                                     
                                     MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.CleanBody, Hazel.SendOption.Reliable, -1);
                                     writer.Write(playerInfo.PlayerId);
@@ -1448,7 +1448,7 @@ namespace TheOtherRoles
                                 Vector2 truePosition = CachedPlayer.LocalPlayer.PlayerControl.GetTruePosition();
                                 Vector2 truePosition2 = component.TruePosition;
                                 if (Vector2.Distance(truePosition2, truePosition) <= CachedPlayer.LocalPlayer.PlayerControl.MaxReportDistance && CachedPlayer.LocalPlayer.PlayerControl.CanMove && !PhysicsHelpers.AnythingBetween(truePosition, truePosition2, Constants.ShipAndObjectsMask, false)) {
-                                    GameData.PlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId);
+                                    NetworkedPlayerInfo playerInfo = GameData.Instance.GetPlayerById(component.ParentId);
 
                                     MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.CleanBody, Hazel.SendOption.Reliable, -1);
                                     writer.Write(playerInfo.PlayerId);
@@ -1796,7 +1796,7 @@ namespace TheOtherRoles
             // Bomber button
             bomberButton = new CustomButton(
                 () => {
-                    if (Helpers.checkMuderAttempt(Bomber.bomber, Bomber.bomber) != MurderAttemptResult.BlankKill) {
+                    if (Helpers.checkMuderAttempt(Bomber.bomber, Bomber.bomber, ignoreMedic: true) != MurderAttemptResult.BlankKill) {
                         var pos = CachedPlayer.LocalPlayer.transform.position;
                         byte[] buff = new byte[sizeof(float) * 2];
                         Buffer.BlockCopy(BitConverter.GetBytes(pos.x), 0, buff, 0 * sizeof(float), sizeof(float));
@@ -1931,7 +1931,6 @@ namespace TheOtherRoles
                     Buffer.BlockCopy(BitConverter.GetBytes(pos.y), 0, buff, 1 * sizeof(float), sizeof(float));
                     
                     if (Yoyo.markedLocation == null) {
-                        TheOtherRolesPlugin.Logger.LogMessage($"marked location is null in button press");
                         MessageWriter writer = AmongUsClient.Instance.StartRpc(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.YoyoMarkLocation, Hazel.SendOption.Reliable);
                         writer.WriteBytesAndSize(buff);
                         writer.EndMessage();
@@ -1942,9 +1941,7 @@ namespace TheOtherRoles
                         yoyoButton.HasEffect = false;
                         yoyoButton.buttonText = "Blink";
                     } else {
-                        TheOtherRolesPlugin.Logger.LogMessage("in else for some reason");
                         // Jump to location
-                        TheOtherRolesPlugin.Logger.LogMessage($"trying to blink!");
                         var exit = (Vector3)Yoyo.markedLocation;
                         if (SubmergedCompatibility.IsSubmerged) {
                             SubmergedCompatibility.ChangeFloor(exit.y > -7);
@@ -2061,7 +2058,7 @@ namespace TheOtherRoles
                 },
                 () => { return true; },
                 () => { return; },
-                Helpers.loadSpriteFromResources("TheOtherRoles.Resources.MinusButton.png", 150f),  // Invisible button!
+                null,  // Invisible button!
                 new Vector3(0.4f, 2.8f, 0),
                 __instance,
                 KeyCode.KeypadPlus
diff --git a/TheOtherRoles/CustomGameModes/GameModePatches.cs b/TheOtherRoles/CustomGameModes/GameModePatches.cs
new file mode 100644 (file)
index 0000000..9aa18d6
--- /dev/null
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Epic.OnlineServices.Presence;
+using HarmonyLib;
+using TheOtherRoles.Utilities;
+using TMPro;
+using UnityEngine;
+using static UnityEngine.UI.Button;
+using UnityEngine.Events;
+using Hazel;
+using TheOtherRoles.Players;
+
+namespace TheOtherRoles.CustomGameModes {
+    [HarmonyPatch]
+    class GameModePatches {
+        /* 
+         Creates a button in the info pane in the lobby to cycle through the game modes of TOR.
+         */
+        [HarmonyPatch(typeof(LobbyInfoPane), nameof(LobbyInfoPane.Update))]
+        class LobbyInfoPanePatch {
+
+            private static GameObject gameModeButton = null;
+            public static void Postfix(LobbyInfoPane __instance) {
+                if (gameModeButton != null||  !AmongUsClient.Instance.AmHost) { return; }
+
+                var template = GameObject.Find("PRIVATE BUTTON");
+                var GameModeText = GameObject.Find("GameModeText");
+                if (template == null || GameModeText== null) { return; }
+                gameModeButton = GameObject.Instantiate(template, template.transform.parent); //, GameModeText.transform);
+                gameModeButton.transform.localPosition = template.transform.localPosition + new Vector3(0f, 0.65f, -2f);
+                gameModeButton.name = "TOR GameModeButton";
+
+                var pButton = gameModeButton.GetComponent<PassiveButton>();
+                pButton.buttonText.text = GameModeText.GetComponent<TextMeshPro>().text;
+                pButton.OnClick.RemoveAllListeners();
+                pButton.OnClick = new ButtonClickedEvent();
+                __instance.StartCoroutine(Effects.Lerp(0.1f, new Action<float>(p => { pButton.buttonText.text = Helpers.cs(Color.yellow, GameModeText.GetComponent<TextMeshPro>().text); })));
+                gameModeButton.transform.GetChild(1).GetComponent<SpriteRenderer>().color = new Color(0.1f, 0.1f, 0.1f);
+                gameModeButton.transform.GetChild(2).GetComponent<SpriteRenderer>().color = new Color(0f, 0f, 0f);
+                pButton.OnClick.AddListener((Action)(() =>
+                {
+                    TORMapOptions.gameMode = (CustomGamemodes)((int)(TORMapOptions.gameMode + 1)  % Enum.GetNames(typeof(CustomGamemodes)).Length);
+                    __instance.StartCoroutine(Effects.Lerp(0.1f, new Action<float>(p => { pButton.buttonText.text = Helpers.cs(Color.yellow, GameModeText.GetComponent<TextMeshPro>().text); })));
+                    MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareGamemode, Hazel.SendOption.Reliable, -1);
+                    writer.Write((byte)TORMapOptions.gameMode);
+                    AmongUsClient.Instance.FinishRpcImmediately(writer);
+                    RPCProcedure.shareGamemode((byte)TORMapOptions.gameMode);
+                }));
+                pButton.OnMouseOut = new UnityEvent();
+                pButton.OnMouseOver = new UnityEvent();
+                pButton.OnMouseOver.AddListener((Action)(() => {
+                    gameModeButton.transform.GetChild(1).gameObject.SetActive(true);
+                    gameModeButton.transform.GetChild(2).gameObject.SetActive(false);
+                }));
+                pButton.OnMouseOut.AddListener((Action)(() => {
+                    gameModeButton.transform.GetChild(1).gameObject.SetActive(false);
+                    gameModeButton.transform.GetChild(2).gameObject.SetActive(true);
+                }));
+
+            }
+        }
+    }
+}
index 633e1400298b8ab268c993ccac8d07de57e439e9..7d0aa063571197e436b17bd7f01296459d72dd03 100644 (file)
@@ -12,6 +12,8 @@ using TheOtherRoles.Players;
 using TheOtherRoles.Utilities;
 using TMPro;
 using UnityEngine;
+using static TheOtherRoles.Snitch;
+using static UnityEngine.GraphicsBuffer;
 
 namespace TheOtherRoles.CustomGameModes {
     [HarmonyPatch]
@@ -122,17 +124,13 @@ namespace TheOtherRoles.CustomGameModes {
             return Helpers.loadSpriteFromResources($"TheOtherRoles.Resources.IntroAnimation.intro_{index + 1000}.png", 150f, cache: false);
         }
 
-        public static void updateWhitelistedObjects() {
+        public static void updateWhitelistedObjects(bool debug=false) {
             string allNames = Helpers.readTextFromResources("TheOtherRoles.Resources.Txt.Props.txt");
-            bool debug = false;
             if (debug) {
                 allNames = Helpers.readTextFromFile(System.IO.Directory.GetCurrentDirectory() + "\\Props.txt");
             }
-            TheOtherRolesPlugin.Logger.LogMessage($"after debug");
+
             whitelistedObjects = allNames.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries).ToList();
-            TheOtherRolesPlugin.Logger.LogMessage($"after split");
-            
-            TheOtherRolesPlugin.Logger.LogMessage($"Last element: {whitelistedObjects.Last()}");
         }
 
 
@@ -172,6 +170,7 @@ namespace TheOtherRoles.CustomGameModes {
             if (poolablesBackground == null) {
                 poolablesBackground = new GameObject("poolablesBackground");
                 poolablesBackground.AddComponent<SpriteRenderer>();
+                poolablesBackground.layer = LayerMask.NameToLayer("UI");
                 if (poolablesBackgroundSprite == null) poolablesBackgroundSprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.poolablesBackground.jpg", 200f);
             }
             poolablesBackground.transform.SetParent(HudManager.Instance.transform);
@@ -193,15 +192,13 @@ namespace TheOtherRoles.CustomGameModes {
                     poolablePlayer.cosmetics.nameText.fontSize = 4;
                 } else {
                     // Display Prop
-                    poolablePlayer.cosmetics.nameText.text = Helpers.cs(Palette.CrewmateBlue, pc.Data.PlayerName); ;
-                    if (isCurrentlyRevealed.ContainsKey(pc.PlayerId)) {
-
-                    }
+                    poolablePlayer.cosmetics.nameText.text = Helpers.cs(Palette.CrewmateBlue, pc.Data.PlayerName);
                 }
                 // update currently revealed:
                 if (isCurrentlyRevealed.ContainsKey(pc.PlayerId)) {
                     if (!revealRenderer.ContainsKey(pc.PlayerId)) {
                         var go = new GameObject($"reveal_renderer_{pc.PlayerId}");
+                        go.layer = LayerMask.NameToLayer("UI");
                         go.AddComponent<SpriteRenderer>();
                         go.transform.SetParent(poolablePlayer.transform.parent, false);
                         go.SetActive(true);
@@ -257,6 +254,7 @@ namespace TheOtherRoles.CustomGameModes {
         }
 
         public static void dangerMeterUpdate() {
+            if (!HudManager.Instance || !HudManager.Instance.DangerMeter) return;
             if (HudManager.Instance.DangerMeter.gameObject.active) {
                 float dist = 55f;
                 float dist2 = 15f;
@@ -358,7 +356,7 @@ namespace TheOtherRoles.CustomGameModes {
                 Collider2D bestCollider = null;
                 float bestDist = 9999;
                 if (whitelistedObjects == null || whitelistedObjects.Count == 0 || verbose) {
-                    updateWhitelistedObjects();
+                    updateWhitelistedObjects(true);
                 }
                 foreach (Collider2D collider in Physics2D.OverlapCircleAll(origin.transform.position, radius)) {
                     if (verbose) {
@@ -522,7 +520,7 @@ namespace TheOtherRoles.CustomGameModes {
 
         [HarmonyPatch(typeof(MapConsole), nameof(MapConsole.CanUse))]
         [HarmonyPostfix]
-        public static void AdminCanUsePostfix(MapConsole __instance, GameData.PlayerInfo pc, ref bool canUse, ref bool couldUse, ref float __result) {
+        public static void AdminCanUsePostfix(MapConsole __instance, NetworkedPlayerInfo pc, ref bool canUse, ref bool couldUse, ref float __result) {
             if (!PropHunt.isPropHuntGM || !PlayerControl.LocalPlayer.Data.Role.IsImpostor) return;
             if (canUse) {
                 if (HudManagerStartPatch.propHuntAdminButton.Timer > 0) {
@@ -565,7 +563,7 @@ namespace TheOtherRoles.CustomGameModes {
         [HarmonyPrefix]
         public static bool CheckClickPatch(KillButton __instance) {
             if (!PropHunt.isPropHuntGM) return true;
-           __instance.DoClick();
+            __instance.DoClick();
             return false;
         }
 
@@ -574,7 +572,7 @@ namespace TheOtherRoles.CustomGameModes {
         [HarmonyPrefix]
         public static bool KillButtonClickPatch(KillButton __instance) {
             if (!PropHunt.isPropHuntGM || __instance.isCoolingDown || PlayerControl.LocalPlayer.Data.IsDead || PlayerControl.LocalPlayer.inVent) return false;
-
+            var targets = PlayerControl.LocalPlayer.Data.Role.GetPlayersInAbilityRangeSorted(RoleBehaviour.GetTempPlayerList(), true).ToArray();
             __instance.SetTarget(PlayerControl.LocalPlayer.Data.Role.GetPlayersInAbilityRangeSorted(RoleBehaviour.GetTempPlayerList(), true).ToArray().FirstOrDefault());
 
             if (__instance.currentTarget == null) {
@@ -587,6 +585,14 @@ namespace TheOtherRoles.CustomGameModes {
             return false;
         }
 
+        [HarmonyPatch(typeof(RoleBehaviour), nameof(RoleBehaviour.IsValidTarget))]
+        [HarmonyPrefix]
+        public static bool IsValidTarget(RoleBehaviour __instance, NetworkedPlayerInfo target,  ref bool __result) {
+            if (!PropHunt.isPropHuntGM) return true;
+            __result = !(target == null) && !target.Disconnected && !target.IsDead && target.PlayerId != __instance.Player.PlayerId && !(target.Role == null) && !(target.Object == null) && !target.Object.inVent && !target.Object.inMovingPlat;
+            return false;
+        }
+
         [HarmonyPatch(typeof(MapBehaviour), nameof(MapBehaviour.Show))]
         [HarmonyPrefix]
         public static void MapBehaviourShowPatch(MapBehaviour __instance, ref MapOptions opts) {
@@ -594,7 +600,7 @@ namespace TheOtherRoles.CustomGameModes {
             if (opts.Mode == MapOptions.Modes.Sabotage) opts.Mode = MapOptions.Modes.Normal;
         }
 
-                
+
         // Disable a lot of stuff
         [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdReportDeadBody))]
         [HarmonyPatch(typeof(Vent), nameof(Vent.SetOutline))]
index 505590c0eb3fc59b829164fee18b0c4ff2c0053a..0b1772e0665995757e06211915c6f1970f470348 100644 (file)
@@ -426,22 +426,21 @@ namespace TheOtherRoles {
 
             // Role Options
             presetSelection = CustomOption.Create(0, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Preset"), presets, null, true);
-            activateRoles = CustomOption.Create(1, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Enable Mod Roles And Block Vanilla Roles"), true, null, true);
-            anyPlayerCanStopStart = CustomOption.Create(2, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Any Player Can Stop The Start"), false, null, false);
+
             
             if (Utilities.EventUtility.canBeEnabled) enableEventMode = CustomOption.Create(10423, Types.General, cs(Color.green, "Enable Special Mode"), true, null, true);
 
             // Using new id's for the options to not break compatibilty with older versions
-            crewmateRolesCountMin = CustomOption.Create(300, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Crewmate Roles"), 15f, 0f, 15f, 1f, null, true);
-            crewmateRolesCountMax = CustomOption.Create(301, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Crewmate Roles"), 15f, 0f, 15f, 1f);
-            crewmateRolesFill = CustomOption.Create(308, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Fill Crewmate Roles\n(Ignores Min/Max)"), false);
+            crewmateRolesCountMin = CustomOption.Create(300, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Crewmate Roles"), 15f, 0f, 15f, 1f, null, true, heading: "Min/Max Roles");
+            crewmateRolesCountMax = CustomOption.Create(301, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Crewmate Roles"), 15f, 0f, 15f, 1f);            
             neutralRolesCountMin = CustomOption.Create(302, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Neutral Roles"), 15f, 0f, 15f, 1f);
             neutralRolesCountMax = CustomOption.Create(303, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Neutral Roles"), 15f, 0f, 15f, 1f);
             impostorRolesCountMin = CustomOption.Create(304, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Impostor Roles"), 15f, 0f, 15f, 1f);
             impostorRolesCountMax = CustomOption.Create(305, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Impostor Roles"), 15f, 0f, 15f, 1f);
             modifiersCountMin = CustomOption.Create(306, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Modifiers"), 15f, 0f, 15f, 1f);
             modifiersCountMax = CustomOption.Create(307, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Modifiers"), 15f, 0f, 15f, 1f);
-            
+            crewmateRolesFill = CustomOption.Create(308, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Fill Crewmate Roles\n(Ignores Min/Max)"), false);
+
             mafiaSpawnRate = CustomOption.Create(18, Types.Impostor, cs(Janitor.color, "Mafia"), rates, null, true);
             janitorCooldown = CustomOption.Create(19, Types.Impostor, "Janitor Cooldown", 30f, 10f, 60f, 2.5f, mafiaSpawnRate);
 
@@ -687,7 +686,7 @@ namespace TheOtherRoles {
             trapperTrapDuration = CustomOption.Create(454, Types.Crewmate, "Trap Duration", 5f, 1f, 15f, 1f, trapperSpawnRate);
 
             // Modifier (1000 - 1999)
-            modifiersAreHidden = CustomOption.Create(1009, Types.Modifier, cs(Color.yellow, "Hide After Death Modifiers"), true, null, true);
+            modifiersAreHidden = CustomOption.Create(1009, Types.Modifier, cs(Color.yellow, "VIP, Bait & Bloody Are Hidden"), true, null, true, heading: cs(Color.yellow, "Hide After Death Modifiers"));
 
             modifierBloody = CustomOption.Create(1000, Types.Modifier, cs(Color.yellow, "Bloody"), rates, null, true);
             modifierBloodyQuantity = CustomOption.Create(1001, Types.Modifier, cs(Color.yellow, "Bloody Quantity"), ratesModifier, modifierBloody);
@@ -734,13 +733,13 @@ namespace TheOtherRoles {
             modifierShifter = CustomOption.Create(1100, Types.Modifier, cs(Color.yellow, "Shifter"), rates, null, true);
 
             // Guesser Gamemode (2000 - 2999)
-            guesserGamemodeCrewNumber = CustomOption.Create(2001, Types.Guesser, cs(Guesser.color, "Number of Crew Guessers"), 15f, 1f, 15f, 1f, null, true);
-            guesserGamemodeNeutralNumber = CustomOption.Create(2002, Types.Guesser, cs(Guesser.color, "Number of Neutral Guessers"), 15f, 1f, 15f, 1f, null, true);
-            guesserGamemodeImpNumber = CustomOption.Create(2003, Types.Guesser, cs(Guesser.color, "Number of Impostor Guessers"), 15f, 1f, 15f, 1f, null, true);
-            guesserForceJackalGuesser = CustomOption.Create(2007, Types.Guesser, "Force Jackal Guesser", false, null, true);
+            guesserGamemodeCrewNumber = CustomOption.Create(2001, Types.Guesser, cs(Guesser.color, "Number of Crew Guessers"), 15f, 1f, 15f, 1f, null, true, heading: "Amount of Guessers");
+            guesserGamemodeNeutralNumber = CustomOption.Create(2002, Types.Guesser, cs(Guesser.color, "Number of Neutral Guessers"), 15f, 1f, 15f, 1f, null);
+            guesserGamemodeImpNumber = CustomOption.Create(2003, Types.Guesser, cs(Guesser.color, "Number of Impostor Guessers"), 15f, 1f, 15f, 1f, null);
+            guesserForceJackalGuesser = CustomOption.Create(2007, Types.Guesser, "Force Jackal Guesser", false, null, true, heading: "Force Guessers");
             guesserGamemodeSidekickIsAlwaysGuesser = CustomOption.Create(2012, Types.Guesser, "Sidekick Is Always Guesser", false, null);
-            guesserForceThiefGuesser = CustomOption.Create(2011, Types.Guesser, "Force Thief Guesser", false, null, true);
-            guesserGamemodeHaveModifier = CustomOption.Create(2004, Types.Guesser, "Guessers Can Have A Modifier", true, null);
+            guesserForceThiefGuesser = CustomOption.Create(2011, Types.Guesser, "Force Thief Guesser", false, null);
+            guesserGamemodeHaveModifier = CustomOption.Create(2004, Types.Guesser, "Guessers Can Have A Modifier", true, null, true, heading: "General Guesser Settings");
             guesserGamemodeNumberOfShots = CustomOption.Create(2005, Types.Guesser, "Guesser Number Of Shots", 3f, 1f, 15f, 1f, null);
             guesserGamemodeHasMultipleShotsPerMeeting = CustomOption.Create(2006, Types.Guesser, "Guesser Can Shoot Multiple Times Per Meeting", false, null);
             guesserGamemodeKillsThroughShield = CustomOption.Create(2008, Types.Guesser, "Guesses Ignore The Medic Shield", true, null);
@@ -764,7 +763,7 @@ namespace TheOtherRoles {
             hideNSeekCanSabotage = CustomOption.Create(3019, Types.HideNSeekMain, cs(Color.yellow, "Enable Sabotages"), false);
             hideNSeekHunterWaiting = CustomOption.Create(3022, Types.HideNSeekMain, cs(Color.yellow, "Time The Hunter Needs To Wait"), 15f, 2.5f, 60f, 2.5f);
 
-            hunterLightCooldown = CustomOption.Create(3005, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Cooldown"), 30f, 5f, 60f, 1f, null, true);
+            hunterLightCooldown = CustomOption.Create(3005, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Cooldown"), 30f, 5f, 60f, 1f, null, true, heading: "Hunter Lights Settings");
             hunterLightDuration = CustomOption.Create(3006, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Duration"), 5f, 1f, 60f, 1f);
             hunterLightVision = CustomOption.Create(3007, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Vision"), 3f, 1f, 5f, 0.25f);
             hunterLightPunish = CustomOption.Create(3008, Types.HideNSeekRoles, cs(Color.red, "Hunter Light Punish In Sec"), 5f, 0f, 30f, 1f);
@@ -775,20 +774,20 @@ namespace TheOtherRoles {
             hunterArrowDuration = CustomOption.Create(3013, Types.HideNSeekRoles, cs(Color.red, "Hunter Arrow Duration"), 5f, 0f, 60f, 1f);
             hunterArrowPunish = CustomOption.Create(3014, Types.HideNSeekRoles, cs(Color.red, "Hunter Arrow Punish In Sec"), 5f, 0f, 30f, 1f);
 
-            huntedShieldCooldown = CustomOption.Create(3015, Types.HideNSeekRoles, cs(Color.gray, "Hunted Shield Cooldown"), 30f, 5f, 60f, 1f, null, true);
+            huntedShieldCooldown = CustomOption.Create(3015, Types.HideNSeekRoles, cs(Color.gray, "Hunted Shield Cooldown"), 30f, 5f, 60f, 1f, null, true, heading: "Hunter Shields Settings");
             huntedShieldDuration = CustomOption.Create(3016, Types.HideNSeekRoles, cs(Color.gray, "Hunted Shield Duration"), 5f, 1f, 60f, 1f);
             huntedShieldRewindTime = CustomOption.Create(3018, Types.HideNSeekRoles, cs(Color.gray, "Hunted Rewind Time"), 3f, 1f, 10f, 1f);
             huntedShieldNumber = CustomOption.Create(3026, Types.HideNSeekRoles, cs(Color.gray, "Hunted Shield Number"), 3f, 1f, 15f, 1f);
 
             // Prop Hunt General Options
             propHuntMap = CustomOption.Create(4020, Types.PropHunt, cs(Color.yellow, "Map"), new string[] { "The Skeld", "Mira", "Polus", "Airship", "Fungle", "Submerged", "LI Map"}, null, true, onChange: ()=> { int map = propHuntMap.selection; if (map >= 3) map++; GameOptionsManager.Instance.currentNormalGameOptions.MapId = (byte)map;});
-            propHuntTimer = CustomOption.Create(4021, Types.PropHunt, cs(Color.yellow, "Timer In Min"), 5f, 1f, 30f, 0.5f);
+            propHuntTimer = CustomOption.Create(4021, Types.PropHunt, cs(Color.yellow, "Timer In Min"), 5f, 1f, 30f, 0.5f, null, true, heading: "General PropHunt Settings");
             propHuntUnstuckCooldown = CustomOption.Create(4011, Types.PropHunt, cs(Color.yellow, "Unstuck Cooldown"), 30f, 2.5f, 60f, 2.5f);
             propHuntUnstuckDuration = CustomOption.Create(4012, Types.PropHunt, cs(Color.yellow, "Unstuck Duration"), 2f, 1f, 60f, 1f);
             propHunterVision = CustomOption.Create(4006, Types.PropHunt, cs(Color.yellow, "Hunter Vision"), 0.5f, 0.25f, 2f, 0.25f);
             propVision = CustomOption.Create(4007, Types.PropHunt, cs(Color.yellow, "Prop Vision"), 2f, 0.25f, 5f, 0.25f);
             // Hunter Options
-            propHuntNumberOfHunters = CustomOption.Create(4000, Types.PropHunt, cs(Color.red, "Number Of Hunters"), 1f, 1f, 5f, 1f, null, true);
+            propHuntNumberOfHunters = CustomOption.Create(4000, Types.PropHunt, cs(Color.red, "Number Of Hunters"), 1f, 1f, 5f, 1f, null, true, heading: "Hunter Settings");
             hunterInitialBlackoutTime = CustomOption.Create(4001, Types.PropHunt, cs(Color.red, "Hunter Initial Blackout Duration"), 10f, 5f, 20f, 1f);
             hunterMissCooldown = CustomOption.Create(4004, Types.PropHunt, cs(Color.red, "Kill Cooldown After Miss"), 10f, 2.5f, 60f, 2.5f);
             hunterHitCooldown = CustomOption.Create(4005, Types.PropHunt, cs(Color.red, "Kill Cooldown After Hit"), 10f, 2.5f, 60f, 2.5f);
@@ -799,7 +798,7 @@ namespace TheOtherRoles {
             propHuntFindCooldown = CustomOption.Create(4023, Types.PropHunt, cs(Color.red, "Find Cooldown"), 60f, 2.5f, 1800f, 2.5f);
             propHuntFindDuration = CustomOption.Create(4024, Types.PropHunt, cs(Color.red, "Find Duration"), 5f, 1f, 15f, 1f);
             // Prop Options
-            propBecomesHunterWhenFound = CustomOption.Create(4003, Types.PropHunt, cs(Palette.CrewmateBlue, "Props Become Hunters When Found"), false, null, true);
+            propBecomesHunterWhenFound = CustomOption.Create(4003, Types.PropHunt, cs(Palette.CrewmateBlue, "Props Become Hunters When Found"), false, null, true, heading: "Prop Settings");
             propHuntInvisEnabled = CustomOption.Create(4013, Types.PropHunt, cs(Palette.CrewmateBlue, "Invisibility Enabled"), true, null, true);
             propHuntInvisCooldown = CustomOption.Create(4014, Types.PropHunt, cs(Palette.CrewmateBlue, "Invisibility Cooldown"), 120f, 10f, 1800f, 2.5f, propHuntInvisEnabled);
             propHuntInvisDuration = CustomOption.Create(4015, Types.PropHunt, cs(Palette.CrewmateBlue, "Invisibility Duration"), 5f, 1f, 30f, 1f, propHuntInvisEnabled);
@@ -811,19 +810,21 @@ namespace TheOtherRoles {
 
 
             // Other options
-            maxNumberOfMeetings = CustomOption.Create(3, Types.General, "Number Of Meetings (excluding Mayor meeting)", 10, 0, 15, 1, null, true);
+            maxNumberOfMeetings = CustomOption.Create(3, Types.General, "Number Of Meetings (excluding Mayor meeting)", 10, 0, 15, 1, null, true, heading: "Gameplay Settings");
+            anyPlayerCanStopStart = CustomOption.Create(2, Types.General, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Any Player Can Stop The Start"), false, null, false);
             blockSkippingInEmergencyMeetings = CustomOption.Create(4, Types.General, "Block Skipping In Emergency Meetings", false);
             noVoteIsSelfVote = CustomOption.Create(5, Types.General, "No Vote Is Self Vote", false, blockSkippingInEmergencyMeetings);
             hidePlayerNames = CustomOption.Create(6, Types.General, "Hide Player Names", false);
             allowParallelMedBayScans = CustomOption.Create(7, Types.General, "Allow Parallel MedBay Scans", false);
             shieldFirstKill = CustomOption.Create(8, Types.General, "Shield Last Game First Kill", false);
             finishTasksBeforeHauntingOrZoomingOut = CustomOption.Create(9, Types.General, "Finish Tasks Before Haunting Or Zooming Out", true);
-            camsNightVision = CustomOption.Create(11, Types.General, "Cams Switch To Night Vision If Lights Are Off", false, null, true);
+            deadImpsBlockSabotage = CustomOption.Create(13, Types.General, "Block Dead Impostor From Sabotaging", false, null, false);
+            camsNightVision = CustomOption.Create(11, Types.General, "Cams Switch To Night Vision If Lights Are Off", false, null, true, heading: "Night Vision Cams");
             camsNoNightVisionIfImpVision = CustomOption.Create(12, Types.General, "Impostor Vision Ignores Night Vision Cams", false, camsNightVision, false);
-            deadImpsBlockSabotage = CustomOption.Create(13, Types.General, cs(Palette.ImpostorRed, "Block Dead Impostor From Sabotaging"), false, null, false);
 
 
-            dynamicMap = CustomOption.Create(500, Types.General, "Play On A Random Map", false, null, true);
+
+            dynamicMap = CustomOption.Create(500, Types.General, "Play On A Random Map", false, null, true, heading: "Random Maps");
             dynamicMapEnableSkeld = CustomOption.Create(501, Types.General, "Skeld", rates, dynamicMap, false);
             dynamicMapEnableMira = CustomOption.Create(502, Types.General, "Mira", rates, dynamicMap, false);
             dynamicMapEnablePolus = CustomOption.Create(503, Types.General, "Polus", rates, dynamicMap, false);
index 3071494f2b5b9fbec5e791a297a60af0b3dd7d8f..5f587171b65b06567fd8819cc778b042369a1abd 100644 (file)
@@ -357,7 +357,7 @@ namespace TheOtherRoles {
             if (Helpers.MushroomSabotageActive()) {
                 var instance = ShipStatus.Instance.CastFast<FungleShipStatus>().specialSabotage;
                 MushroomMixupSabotageSystem.CondensedOutfit condensedOutfit = instance.currentMixups[target.PlayerId];
-                GameData.PlayerOutfit playerOutfit = instance.ConvertToPlayerOutfit(condensedOutfit);
+                NetworkedPlayerInfo.PlayerOutfit playerOutfit = instance.ConvertToPlayerOutfit(condensedOutfit);
                 target.MixUpOutfit(playerOutfit);
             } else
                 target.setLook(target.Data.PlayerName, target.Data.DefaultOutfit.ColorId, target.Data.DefaultOutfit.HatId, target.Data.DefaultOutfit.VisorId, target.Data.DefaultOutfit.SkinId, target.Data.DefaultOutfit.PetId, enforceNightVisionUpdate);
@@ -450,7 +450,7 @@ namespace TheOtherRoles {
             return roleCouldUse;
         }
 
-        public static MurderAttemptResult checkMuderAttempt(PlayerControl killer, PlayerControl target, bool blockRewind = false, bool ignoreBlank = false, bool ignoreIfKillerIsDead = false) {
+        public static MurderAttemptResult checkMuderAttempt(PlayerControl killer, PlayerControl target, bool blockRewind = false, bool ignoreBlank = false, bool ignoreIfKillerIsDead = false, bool ignoreMedic = false) {
             var targetRole = RoleInfo.getRoleInfoForPlayer(target, false).FirstOrDefault();
 
             // Modified vanilla checks
@@ -474,7 +474,7 @@ namespace TheOtherRoles {
             }
 
             // Block impostor shielded kill
-            if (Medic.shielded != null && Medic.shielded == target) {
+            if (!ignoreMedic && Medic.shielded != null && Medic.shielded == target) {
                 MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)CustomRPC.ShieldedMurderAttempt, Hazel.SendOption.Reliable, -1);
                 AmongUsClient.Instance.FinishRpcImmediately(writer);
                 RPCProcedure.shieldedMurderAttempt();
@@ -606,10 +606,15 @@ namespace TheOtherRoles {
                 if (cam != null && cam.gameObject.name == "UI Camera") cam.orthographicSize = orthographicSize;  // The UI is scaled too, else we cant click the buttons. Downside: map is super small.
             }
 
-            if (HudManagerStartPatch.zoomOutButton != null) {
-                HudManagerStartPatch.zoomOutButton.Sprite = zoomOutStatus ? Helpers.loadSpriteFromResources("TheOtherRoles.Resources.PlusButton.png", 75f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.MinusButton.png", 150f);
-                HudManagerStartPatch.zoomOutButton.PositionOffset = zoomOutStatus ? new Vector3(0f, 3f, 0) : new Vector3(0.4f, 2.8f, 0);
+            var tzGO = GameObject.Find("TOGGLEZOOMBUTTON");
+            if (tzGO != null) {
+                var rend = tzGO.transform.Find("Inactive").GetComponent<SpriteRenderer>();
+                var rendActive = tzGO.transform.Find("Active").GetComponent<SpriteRenderer>();
+                rend.sprite = zoomOutStatus ? Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Plus_Button.png", 100f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_Button.png", 100f);
+                rendActive.sprite = zoomOutStatus ? Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Plus_ButtonActive.png", 100f) : Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_ButtonActive.png", 100f);
+                tzGO.transform.localScale = new Vector3(1.2f, 1.2f, 1f) * (zoomOutStatus ? 4 : 1);
             }
+
             ResolutionManager.ResolutionChanged.Invoke((float)Screen.width / Screen.height, Screen.width, Screen.height, Screen.fullScreen); // This will move button positions to the correct position.
         }
 
@@ -654,7 +659,7 @@ namespace TheOtherRoles {
             }
         }
 
-        public static bool hasImpVision(GameData.PlayerInfo player) {
+        public static bool hasImpVision(NetworkedPlayerInfo player) {
             return player.Role.IsImpostor
                 || ((Jackal.jackal != null && Jackal.jackal.PlayerId == player.PlayerId || Jackal.formerJackals.Any(x => x.PlayerId == player.PlayerId)) && Jackal.hasImpostorVision)
                 || (Sidekick.sidekick != null && Sidekick.sidekick.PlayerId == player.PlayerId && Sidekick.hasImpostorVision)
index bc502cea0279ccb8043e2072640abec27f8d6089..066a0bff343840ff804f5a6f39d1e626076b0864 100644 (file)
@@ -33,7 +33,7 @@ namespace TheOtherRoles
     public class TheOtherRolesPlugin : BasePlugin
     {
         public const string Id = "me.eisbison.theotherroles";
-        public const string VersionString = "4.5.3";
+        public const string VersionString = "4.6.0";
         public static uint betaDays = 0;  // amount of days for the build to be usable (0 for infinite!)
 
         public static Version Version = Version.Parse(VersionString);
@@ -54,6 +54,7 @@ namespace TheOtherRoles
         public static ConfigEntry<bool> EnableSoundEffects { get; set; }
         public static ConfigEntry<bool> EnableHorseMode { get; set; }
         public static ConfigEntry<bool> ShowVentsOnMap { get; set; }
+        public static ConfigEntry<bool> ShowChatNotifications { get; set; }
         public static ConfigEntry<string> Ip { get; set; }
         public static ConfigEntry<ushort> Port { get; set; }
         public static ConfigEntry<string> ShowPopUpVersion { get; set; }
@@ -108,11 +109,13 @@ namespace TheOtherRoles
             EnableHorseMode = Config.Bind("Custom", "Enable Horse Mode", false);
             ShowPopUpVersion = Config.Bind("Custom", "Show PopUp", "0");
             ShowVentsOnMap = Config.Bind("Custom", "Show vent positions on minimap", false);
-            
+            ShowChatNotifications = Config.Bind("Custom", "Show Chat Notifications", true);
+
             Ip = Config.Bind("Custom", "Custom Server IP", "127.0.0.1");
             Port = Config.Bind("Custom", "Custom Server Port", (ushort)22023);
             defaultRegions = ServerManager.DefaultRegions;
-
+            // Removes vanilla Servers
+            ServerManager.DefaultRegions = new Il2CppReferenceArray<IRegionInfo>(new IRegionInfo[0]);
             UpdateRegions();
 
             DebugMode = Config.Bind("Custom", "Enable Debug Mode", "false");
@@ -178,12 +181,12 @@ namespace TheOtherRoles
 
 
             // Spawn dummys
-            if (Input.GetKeyDown(KeyCode.F)) {
+            /*if (Input.GetKeyDown(KeyCode.F)) {
                 var playerControl = UnityEngine.Object.Instantiate(AmongUsClient.Instance.PlayerPrefab);
                 var i = playerControl.PlayerId = (byte) GameData.Instance.GetAvailableId();
 
                 bots.Add(playerControl);
-                GameData.Instance.AddPlayer(playerControl);
+                GameData.Instance.AddPlayer(playerControl, new InnerNet.ClientData(0));
                 AmongUsClient.Instance.Spawn(playerControl, -2, InnerNet.SpawnFlags.None);
                 
                 playerControl.transform.position = CachedPlayer.LocalPlayer.transform.position;
@@ -191,8 +194,8 @@ namespace TheOtherRoles
                 playerControl.NetTransform.enabled = false;
                 playerControl.SetName(RandomString(10));
                 playerControl.SetColor((byte) random.Next(Palette.PlayerColors.Length));
-                GameData.Instance.RpcSetTasks(playerControl.PlayerId, new byte[0]);
-            }
+                playerControl.Data.RpcSetTasks(new byte[0]);
+            }*/
 
             // Terminate round
             if(Input.GetKeyDown(KeyCode.L)) {
index 83cce2d659d976e8565c724cf354e5a2d0a69c13..7df9c307192080b672f45973a2a16f562e74a797 100644 (file)
@@ -19,6 +19,7 @@ namespace TheOtherRoles{
         public static bool enableHorseMode = false;
         public static bool shieldFirstKill = false;
         public static bool ShowVentsOnMap = true;
+        public static bool ShowChatNotifications = true;
         public static CustomGamemodes gameMode = CustomGamemodes.Classic;
 
         // Updating values
@@ -54,7 +55,8 @@ namespace TheOtherRoles{
             enableSoundEffects = TheOtherRolesPlugin.EnableSoundEffects.Value;
             enableHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
             ShowVentsOnMap = TheOtherRolesPlugin.ShowVentsOnMap.Value;
-            
+            ShowChatNotifications = TheOtherRolesPlugin.ShowChatNotifications.Value;
+
             //Patches.ShouldAlwaysHorseAround.isHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
         }
     }
index 42b3591e4195996c603af7a2a8685a610acacf4f..4f994a7057ef6daf24111a9b32b799cc88251451 100644 (file)
@@ -19,8 +19,8 @@ namespace TheOtherRoles.Modules;
 
 public class BepInExUpdater : MonoBehaviour
 {
-    public const string RequiredBepInExVersion = "6.0.0-be.688+49015217f3becf052d33fa4658ac19229f5daa3a";
-    public const string BepInExDownloadURL = "https://builds.bepinex.dev/projects/bepinex_be/688/BepInEx-Unity.IL2CPP-win-x86-6.0.0-be.688%2B4901521.zip";
+    public const string RequiredBepInExVersion = "6.0.0-be.692+851521cc126e4f9d841d2d9bfe857558f0395939";
+    public const string BepInExDownloadURL = "https://builds.bepinex.dev/projects/bepinex_be/692/BepInEx-Unity.IL2CPP-win-x86-6.0.0-be.692%2B851521c.zip";
     public static bool UpdateRequired => Paths.BepInExVersion.ToString() != RequiredBepInExVersion;
 
     public void Awake()
index 4cabe69da4af41b4cf9ff08526478e484a83267a..331a91363c0d64687f7f7023a92a34fa398b6119 100644 (file)
@@ -115,7 +115,7 @@ namespace TheOtherRoles.Modules {
         public static class SetBubbleName { 
             public static void Postfix(ChatBubble __instance, [HarmonyArgument(0)] string playerName) {
                 PlayerControl sourcePlayer = PlayerControl.AllPlayerControls.ToArray().ToList().FirstOrDefault(x => x.Data != null && x.Data.PlayerName.Equals(playerName));
-                if (CachedPlayer.LocalPlayer != null && CachedPlayer.LocalPlayer.Data.Role.IsImpostor && (Spy.spy != null && sourcePlayer.PlayerId == Spy.spy.PlayerId || Sidekick.sidekick != null && Sidekick.wasTeamRed && sourcePlayer.PlayerId == Sidekick.sidekick.PlayerId || Jackal.jackal != null && Jackal.wasTeamRed && sourcePlayer.PlayerId == Jackal.jackal.PlayerId) && __instance != null) __instance.NameText.color = Palette.ImpostorRed;
+                if (sourcePlayer != null && CachedPlayer.LocalPlayer != null && CachedPlayer.LocalPlayer.Data?.Role?.IsImpostor == true && (Spy.spy != null && sourcePlayer.PlayerId == Spy.spy.PlayerId || Sidekick.sidekick != null && Sidekick.wasTeamRed && sourcePlayer.PlayerId == Sidekick.sidekick.PlayerId || Jackal.jackal != null && Jackal.wasTeamRed && sourcePlayer.PlayerId == Jackal.jackal.PlayerId) && __instance != null) __instance.NameText.color = Palette.ImpostorRed;
             }
         }
 
index 495af2413b144e2dc1989b4e3bf5f650455d6c78..980055350afa949d1ae641de13a78d835952c006 100644 (file)
@@ -184,6 +184,36 @@ namespace TheOtherRoles.Modules {
                     return true;
                 }
             }
+
+            [HarmonyPatch(typeof(ChatNotification), nameof(ChatNotification.SetUp))]
+            private class ChatNotificationColorsPatch {
+                public static bool Prefix(ChatNotification __instance, PlayerControl sender, string text) {
+                    if (ShipStatus.Instance && !TORMapOptions.ShowChatNotifications) {
+                        return false;
+                    }
+                    __instance.timeOnScreen = 5f;
+                    __instance.gameObject.SetActive(true);
+                    __instance.SetCosmetics(sender.Data);
+                    string str;
+                    Color color;
+                    try {
+                        str = ColorUtility.ToHtmlStringRGB(Palette.TextColors[__instance.player.ColorId]);
+                        color = Palette.TextOutlineColors[__instance.player.ColorId];
+                    } catch {
+                        Color32 c = Palette.PlayerColors[__instance.player.ColorId];
+                        str = ColorUtility.ToHtmlStringRGB(c);
+                        
+                        color = c.r + c.g + c.b  > 180 ? Palette.Black : Palette.White;
+                        TheOtherRolesPlugin.Logger.LogMessage($"{c.r}, {c.g}, {c.b}");
+                    }
+                    __instance.playerColorText.text = __instance.player.ColorBlindName;
+                    __instance.playerNameText.text = "<color=#" + str + ">" + (string.IsNullOrEmpty(sender.Data.PlayerName) ? "..." : sender.Data.PlayerName);
+                    __instance.playerNameText.outlineColor = color;
+                    __instance.chatText.text = text;
+                    return false;
+                }
+            }
+
             [HarmonyPatch(typeof(PlayerTab), nameof(PlayerTab.OnEnable))]
             private static class PlayerTabEnablePatch {
                 public static void Postfix(PlayerTab __instance) { // Replace instead
@@ -224,7 +254,7 @@ namespace TheOtherRoles.Modules {
             [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CheckColor))]
             private static class PlayerControlCheckColorPatch {
                 private static bool isTaken(PlayerControl player, uint color) {
-                    foreach (GameData.PlayerInfo p in GameData.Instance.AllPlayers.GetFastEnumerator())
+                    foreach (NetworkedPlayerInfo p in GameData.Instance.AllPlayers.GetFastEnumerator())
                         if (!p.Disconnected && p.PlayerId != player.PlayerId && p.DefaultOutfit.ColorId == color)
                             return true;
                     return false;
index ecfaa72b6e60c1f57661dad84a4b7936893c0bea..958ca02427ed4b38bc56738dc0a1704edd2654de 100644 (file)
@@ -219,7 +219,6 @@ internal static class HatParentPatches
         {
             spriteAnimNodeSync.NodeId = __instance.Hat.NoBounce ? 1 : 0;
         }
-
         if (__instance.Hat.InFront)
         {
             __instance.BackLayer.enabled = false;
@@ -240,8 +239,7 @@ internal static class HatParentPatches
             __instance.FrontLayer.sprite = null;
             __instance.BackLayer.sprite = asset.MainImage;
         }
-
-        if (!__instance.options.Initialized || !__instance.HideHat()) return false;
+        if (/*!__instance.options.Initialized ||*/ !__instance.HideHat()) return false;
         __instance.FrontLayer.enabled = false;
         __instance.BackLayer.enabled = false;
         return false;
index 5a258e4c8ea2ce29634c2cb3188ee6b88ccf5437..ca2587b3aaedb41c3fe2a4c37ca3f37245e32544 100644 (file)
@@ -10,14 +10,15 @@ using Object = UnityEngine.Object;
 
 namespace TheOtherRoles.Modules.CustomHats.Patches;
 
-[HarmonyPatch(typeof(HatsTab))]
+[HarmonyPatch]
 internal static class HatsTabPatches
 {
     private static TextMeshPro textTemplate;
-    
-    [HarmonyPatch(nameof(HatsTab.OnEnable))]
-    [HarmonyPostfix]
-    private static void OnEnablePostfix(HatsTab __instance)
+
+
+    [HarmonyPatch(typeof(HatsTab), nameof(HatsTab.OnEnable))]
+    [HarmonyPrefix]
+    private static bool OnEnablePrefix(HatsTab __instance)
     {
         for (var i = 0; i < __instance.scroller.Inner.childCount; i++)
         {
@@ -66,6 +67,7 @@ internal static class HatsTabPatches
         }
         
         __instance.scroller.ContentYBounds.max = -(yOffset + 4.1f);
+        return false;
     }
 
     private static float CreateHatPackage(List<Tuple<HatData, HatExtension>> hats, string packageName, float yStart,
@@ -106,7 +108,7 @@ internal static class HatsTabPatches
                 colorChip.Button.OnClick.AddListener((Action)(() => hatsTab.SelectHat(hat)));
             }
             colorChip.Button.ClickMask = hatsTab.scroller.Hitbox;
-            colorChip.Inner.SetMaskType(PlayerMaterial.MaskType.ScrollingUI);
+            colorChip.Inner.SetMaskType(PlayerMaterial.MaskType.SimpleUI);
             hatsTab.UpdateMaterials(colorChip.Inner.FrontLayer, hat);
             var background = colorChip.transform.FindChild("Background");
             var foreground = colorChip.transform.FindChild("ForeGround");
index eec9887f9937b1e55848a9dee55d9703f51b891a..dd5b4bd69d9c79f1af8b218e3d2d56123446f174 100644 (file)
@@ -17,6 +17,7 @@ using AmongUs.GameOptions;
 using BepInEx.Unity.IL2CPP;
 using BepInEx;
 using static ShipStatus;
+using TMPro;
 
 namespace TheOtherRoles {
     public class CustomOption {
@@ -48,10 +49,11 @@ namespace TheOtherRoles {
         public bool isHeader;
         public CustomOptionType type;
         public Action onChange = null;
+        public string heading = "";
 
         // Option creation
 
-        public CustomOption(int id, CustomOptionType type, string name,  System.Object[] selections, System.Object defaultValue, CustomOption parent, bool isHeader, Action onChange = null) {
+        public CustomOption(int id, CustomOptionType type, string name,  System.Object[] selections, System.Object defaultValue, CustomOption parent, bool isHeader, Action onChange = null, string heading = "") {
             this.id = id;
             this.name = parent == null ? name : "- " + name;
             this.selections = selections;
@@ -61,6 +63,7 @@ namespace TheOtherRoles {
             this.isHeader = isHeader;
             this.type = type;
             this.onChange = onChange;
+            this.heading = heading;
             selection = 0;
             if (id != 0) {
                 entry = TheOtherRolesPlugin.Instance.Config.Bind($"Preset{preset}", id.ToString(), defaultSelection);
@@ -69,19 +72,19 @@ namespace TheOtherRoles {
             options.Add(this);
         }
 
-        public static CustomOption Create(int id, CustomOptionType type, string name, string[] selections, CustomOption parent = null, bool isHeader = false, Action onChange = null) {
-            return new CustomOption(id, type, name, selections, "", parent, isHeader, onChange);
+        public static CustomOption Create(int id, CustomOptionType type, string name, string[] selections, CustomOption parent = null, bool isHeader = false, Action onChange = null, string heading = "") {
+            return new CustomOption(id, type, name, selections, "", parent, isHeader, onChange, heading);
         }
 
-        public static CustomOption Create(int id, CustomOptionType type, string name, float defaultValue, float min, float max, float step, CustomOption parent = null, bool isHeader = false, Action onChange = null) {
+        public static CustomOption Create(int id, CustomOptionType type, string name, float defaultValue, float min, float max, float step, CustomOption parent = null, bool isHeader = false, Action onChange = null, string heading = "") {
             List<object> selections = new();
             for (float s = min; s <= max; s += step)
                 selections.Add(s);
-            return new CustomOption(id, type, name, selections.ToArray(), defaultValue, parent, isHeader, onChange);
+            return new CustomOption(id, type, name, selections.ToArray(), defaultValue, parent, isHeader, onChange, heading);
         }
 
-        public static CustomOption Create(int id, CustomOptionType type, string name, bool defaultValue, CustomOption parent = null, bool isHeader = false, Action onChange = null) {
-            return new CustomOption(id, type, name, new string[]{"Off", "On"}, defaultValue ? "On" : "Off", parent, isHeader, onChange);
+        public static CustomOption Create(int id, CustomOptionType type, string name, bool defaultValue, CustomOption parent = null, bool isHeader = false, Action onChange = null, string heading = "") {
+            return new CustomOption(id, type, name, new string[]{"Off", "On"}, defaultValue ? "On" : "Off", parent, isHeader, onChange, heading);
         }
 
         // Static behaviour
@@ -107,13 +110,19 @@ namespace TheOtherRoles {
             vanillaSettings.Value = Convert.ToBase64String(GameOptionsManager.Instance.gameOptionsFactory.ToBytes(GameManager.Instance.LogicOptions.currentGameOptions, false));
         }
 
-        public static void loadVanillaOptions() {
+        public static bool loadVanillaOptions() {
             string optionsString = vanillaSettings.Value;
-            if (optionsString == "") return;
-            GameOptionsManager.Instance.GameHostOptions = GameOptionsManager.Instance.gameOptionsFactory.FromBytes(Convert.FromBase64String(optionsString));
+            if (optionsString == "") return false;
+            IGameOptions gameOptions = GameOptionsManager.Instance.gameOptionsFactory.FromBytes(Convert.FromBase64String(optionsString));
+            if (gameOptions.Version < 8) {
+                TheOtherRolesPlugin.Logger.LogMessage("tried to paste old settings, not doing this!");
+                return false;
+            } 
+            GameOptionsManager.Instance.GameHostOptions = gameOptions;
             GameOptionsManager.Instance.CurrentGameOptions = GameOptionsManager.Instance.GameHostOptions;
             GameManager.Instance.LogicOptions.SetGameOptions(GameOptionsManager.Instance.CurrentGameOptions);
             GameManager.Instance.LogicOptions.SyncOptions();
+            return true;
         }
 
         public static void ShareOptionChange(uint optionId) {
@@ -163,10 +172,18 @@ namespace TheOtherRoles {
             return selection + 1;
         }
 
-        // Option changes
 
-        public void updateSelection(int newSelection) {
-            selection = Mathf.Clamp((newSelection + selections.Length) % selections.Length, 0, selections.Length - 1);
+        public void updateSelection(int newSelection, bool notifyUsers = true) {
+            newSelection = Mathf.Clamp((newSelection + selections.Length) % selections.Length, 0, selections.Length - 1);
+            if (AmongUsClient.Instance?.AmClient == true && notifyUsers && selection != newSelection) {
+                DestroyableSingleton<HudManager>.Instance.Notifier.AddSettingsChangeMessage((StringNames)(this.id + 6000), selections[newSelection].ToString(), false);
+                try {
+                    if (GameStartManager.Instance != null && GameStartManager.Instance.LobbyInfoPane != null && GameStartManager.Instance.LobbyInfoPane.LobbyViewSettingsPane != null && GameStartManager.Instance.LobbyInfoPane.LobbyViewSettingsPane.gameObject.activeSelf) {
+                        LobbyViewSettingsPaneChangeTabPatch.Postfix(GameStartManager.Instance.LobbyInfoPane.LobbyViewSettingsPane, GameStartManager.Instance.LobbyInfoPane.LobbyViewSettingsPane.currentTab);
+                    }
+                } catch { }
+            }
+            selection = newSelection;
             try {
                 if (onChange != null) onChange();
             } catch { }
@@ -208,9 +225,11 @@ namespace TheOtherRoles {
             }
         }
 
-        public static void deserializeOptions(byte[] inputValues) {
+        public static int deserializeOptions(byte[] inputValues) {
             BinaryReader reader = new BinaryReader(new MemoryStream(inputValues));
             int lastId = -1;
+            bool somethingApplied = false;
+            int errors = 0;
             while (reader.BaseStream.Position < inputValues.Length) {
                 try {
                     int selection = reader.ReadByte();
@@ -224,12 +243,20 @@ namespace TheOtherRoles {
                     }
                     if (id == 0) continue;
                     lastId = id;
-                    CustomOption option = CustomOption.options.First(option => option.id == id);
-                    option.updateSelection(selection);
+                    CustomOption option = options.First(option => option.id == id);
+                    option.entry = TheOtherRolesPlugin.Instance.Config.Bind($"Preset{preset}", option.id.ToString(), option.defaultSelection);
+                    option.selection = selection;
+                    if (option.optionBehaviour != null && option.optionBehaviour is StringOption stringOption) {
+                        stringOption.oldValue = stringOption.Value = option.selection;
+                        stringOption.ValueText.text = option.selections[option.selection].ToString();
+                    }
+                    somethingApplied = true;
                 } catch (Exception e) {
-                    TheOtherRolesPlugin.Logger.LogWarning($"{e}: while deserializing - tried to paste invalid settings!");
+                    TheOtherRolesPlugin.Logger.LogWarning($"id:{lastId}:{e}: while deserializing - tried to paste invalid settings!");
+                    errors++;
                 }
             }
+            return Convert.ToInt32(somethingApplied) + (errors > 0 ? 0 : 1);
         }
 
         // Copy to or paste from clipboard (as string)
@@ -237,587 +264,527 @@ namespace TheOtherRoles {
             GUIUtility.systemCopyBuffer = $"{TheOtherRolesPlugin.VersionString}!{Convert.ToBase64String(serializeOptions())}!{vanillaSettings.Value}";
         }
 
-        public static bool pasteFromClipboard() {
+        public static int pasteFromClipboard() {
             string allSettings = GUIUtility.systemCopyBuffer;
+            int torOptionsFine = 0;
+            bool vanillaOptionsFine = false;
             try {
                 var settingsSplit = allSettings.Split("!");
-                string versionInfo = settingsSplit[0];
+                Version versionInfo = Version.Parse(settingsSplit[0]);
                 string torSettings = settingsSplit[1];
                 string vanillaSettingsSub = settingsSplit[2];
-                deserializeOptions(Convert.FromBase64String(torSettings));
-
-                vanillaSettings.Value = vanillaSettingsSub;
-                loadVanillaOptions();
-                return true;
+                torOptionsFine = deserializeOptions(Convert.FromBase64String(torSettings));
+                ShareOptionSelections();
+                if (TheOtherRolesPlugin.Version > versionInfo && versionInfo < Version.Parse("4.6.0")) {
+                    vanillaOptionsFine = false;
+                    FastDestroyableSingleton<HudManager>.Instance.Chat.AddChat(PlayerControl.LocalPlayer, "Host Info: Pasting vanilla settings failed, TOR Options applied!");
+                } else {
+                    vanillaSettings.Value = vanillaSettingsSub;
+                    vanillaOptionsFine = loadVanillaOptions();
+                }
             } catch (Exception e) {
-                TheOtherRolesPlugin.Logger.LogWarning($"{e}: tried to paste invalid settings!");
+                TheOtherRolesPlugin.Logger.LogWarning($"{e}: tried to paste invalid settings!\n{allSettings}");
+                string errorStr = allSettings.Length > 2 ? allSettings.Substring(0, 3) : "(empty clipboard) ";
+                FastDestroyableSingleton<HudManager>.Instance.Chat.AddChat(PlayerControl.LocalPlayer, $"Host Info: You tried to paste invalid settings: \"{errorStr}...\"");
                 SoundEffectsManager.Load();
                 SoundEffectsManager.play("fail");
-                return false;
             }
+            return Convert.ToInt32(vanillaOptionsFine) + torOptionsFine;
         }
     }
 
-    [HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Start))]
-    class GameOptionsMenuStartPatch {
-        public static void Postfix(GameOptionsMenu __instance) {
 
-            switch (TORMapOptions.gameMode) {
-                case CustomGamemodes.Classic:
-                    createClassicTabs(__instance);
-                    break;
-                case CustomGamemodes.Guesser:
-                    createGuesserTabs(__instance);
-                    break;
-                case CustomGamemodes.HideNSeek:
-                    createHideNSeekTabs(__instance);
-                    break;
-                case CustomGamemodes.PropHunt:
-                    createPropHuntTabs(__instance);
-                    break;
-            }
 
-            // create copy to clipboard and paste from clipboard buttons.
-            var template = GameObject.Find("CloseButton");
-            var copyButton = GameObject.Instantiate(template, template.transform.parent);
-            copyButton.transform.localPosition += Vector3.down * 0.8f;
-            var copyButtonPassive = copyButton.GetComponent<PassiveButton>();
-            var copyButtonRenderer = copyButton.GetComponent<SpriteRenderer>();
-            copyButtonRenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CopyButton.png", 175f);
-            copyButtonPassive.OnClick.RemoveAllListeners();
-            copyButtonPassive.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
-            copyButtonPassive.OnClick.AddListener((System.Action)(() => {
-                copyToClipboard();
-                copyButtonRenderer.color = Color.green;
-                __instance.StartCoroutine(Effects.Lerp(1f, new System.Action<float>((p) => {
-                    if (p > 0.95)
-                        copyButtonRenderer.color = Color.white;
-                })));
-            }));
-            var pasteButton = GameObject.Instantiate(template, template.transform.parent);
-            pasteButton.transform.localPosition += Vector3.down * 1.6f;
-            var pasteButtonPassive = pasteButton.GetComponent<PassiveButton>();
-            var pasteButtonRenderer = pasteButton.GetComponent<SpriteRenderer>();
-            pasteButtonRenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.PasteButton.png", 175f);
-            pasteButtonPassive.OnClick.RemoveAllListeners();
-            pasteButtonPassive.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
-            pasteButtonPassive.OnClick.AddListener((System.Action)(() => {
-                pasteButtonRenderer.color = Color.yellow;
-                bool success = pasteFromClipboard();
-                pasteButtonRenderer.color = success ? Color.green : Color.red;
-                __instance.StartCoroutine(Effects.Lerp(1f, new System.Action<float>((p) => {
-                    if (p > 0.95)
-                        pasteButtonRenderer.color = Color.white;
-                })));
-            }));
 
+    [HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.ChangeTab))]
+    class GameOptionsMenuChangeTabPatch {
+        public static void Postfix(GameSettingMenu __instance, int tabNum, bool previewOnly) {
+            if (previewOnly) return;
+            foreach (var tab in GameOptionsMenuStartPatch.currentTabs) {
+                if (tab != null)
+                    tab.SetActive(false);
+            }
+            foreach (var pbutton in GameOptionsMenuStartPatch.currentButtons) {
+                pbutton.SelectButton(false);
+            }
+            if (tabNum > 2) {
+                tabNum -= 3;
+                GameOptionsMenuStartPatch.currentTabs[tabNum].SetActive(true);
+                GameOptionsMenuStartPatch.currentButtons[tabNum].SelectButton(true);
+            }
         }
+    }
 
-        private static void createClassicTabs(GameOptionsMenu __instance) {
-            bool isReturn = setNames(
-                new Dictionary<string, string>() {
-                    ["TORSettings"] = "The Other Roles Settings",
-                    ["ImpostorSettings"] = "Impostor Roles Settings",
-                    ["NeutralSettings"] = "Neutral Roles Settings",
-                    ["CrewmateSettings"] = "Crewmate Roles Settings",
-                    ["ModifierSettings"] = "Modifier Settings"
-                });
-
-            if (isReturn) return;
-
-            // Setup TOR tab
-            var template = UnityEngine.Object.FindObjectsOfType<StringOption>().FirstOrDefault();
-            if (template == null) return;
-            var gameSettings = GameObject.Find("Game Settings");
-            var gameSettingMenu = UnityEngine.Object.FindObjectsOfType<GameSettingMenu>().FirstOrDefault();
-
-            var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var torMenu = getMenu(torSettings, "TORSettings");
-
-            var impostorSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var impostorMenu = getMenu(impostorSettings, "ImpostorSettings");
-
-            var neutralSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var neutralMenu = getMenu(neutralSettings, "NeutralSettings");
-
-            var crewmateSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var crewmateMenu = getMenu(crewmateSettings, "CrewmateSettings");
-
-            var modifierSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var modifierMenu = getMenu(modifierSettings, "ModifierSettings");
-
-            var roleTab = GameObject.Find("RoleTab");
-            var gameTab = GameObject.Find("GameTab");
-
-            var torTab = UnityEngine.Object.Instantiate(roleTab, roleTab.transform.parent);
-            var torTabHighlight = getTabHighlight(torTab, "TheOtherRolesTab", "TheOtherRoles.Resources.TabIcon.png");
-
-            var impostorTab = UnityEngine.Object.Instantiate(roleTab, torTab.transform);
-            var impostorTabHighlight = getTabHighlight(impostorTab, "ImpostorTab", "TheOtherRoles.Resources.TabIconImpostor.png");
-
-            var neutralTab = UnityEngine.Object.Instantiate(roleTab, impostorTab.transform);
-            var neutralTabHighlight = getTabHighlight(neutralTab, "NeutralTab", "TheOtherRoles.Resources.TabIconNeutral.png");
-
-            var crewmateTab = UnityEngine.Object.Instantiate(roleTab, neutralTab.transform);
-            var crewmateTabHighlight = getTabHighlight(crewmateTab, "CrewmateTab", "TheOtherRoles.Resources.TabIconCrewmate.png");
-
-            var modifierTab = UnityEngine.Object.Instantiate(roleTab, crewmateTab.transform);
-            var modifierTabHighlight = getTabHighlight(modifierTab, "ModifierTab", "TheOtherRoles.Resources.TabIconModifier.png");
-
-            // Position of Tab Icons
-            gameTab.transform.position += Vector3.left * 3f;
-            roleTab.transform.position += Vector3.left * 3f;
-            torTab.transform.position += Vector3.left * 2f;
-            impostorTab.transform.localPosition = Vector3.right * 1f;
-            neutralTab.transform.localPosition = Vector3.right * 1f;
-            crewmateTab.transform.localPosition = Vector3.right * 1f;
-            modifierTab.transform.localPosition = Vector3.right * 1f;
-
-            var tabs = new GameObject[] { gameTab, roleTab, torTab, impostorTab, neutralTab, crewmateTab, modifierTab };
-            var settingsHighlightMap = new Dictionary<GameObject, SpriteRenderer> {
-                [gameSettingMenu.RegularGameSettings] = gameSettingMenu.GameSettingsHightlight,
-                [gameSettingMenu.RolesSettings.gameObject] = gameSettingMenu.RolesSettingsHightlight,
-                [torSettings.gameObject] = torTabHighlight,
-                [impostorSettings.gameObject] = impostorTabHighlight,
-                [neutralSettings.gameObject] = neutralTabHighlight,
-                [crewmateSettings.gameObject] = crewmateTabHighlight,
-                [modifierSettings.gameObject] = modifierTabHighlight
-            };
-            for (int i = 0; i < tabs.Length; i++) {
-                var button = tabs[i].GetComponentInChildren<PassiveButton>();
-                if (button == null) continue;
-                int copiedIndex = i;
-                button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
-                button.OnClick.AddListener((System.Action)(() => {
-                    setListener(settingsHighlightMap, copiedIndex);
-                }));
+    [HarmonyPatch(typeof(LobbyViewSettingsPane), nameof(LobbyViewSettingsPane.SetTab))]
+    class LobbyViewSettingsPaneRefreshTabPatch {
+        public static bool Prefix(LobbyViewSettingsPane __instance) {
+            if ((int)__instance.currentTab < 15) {
+                LobbyViewSettingsPaneChangeTabPatch.Postfix(__instance, __instance.currentTab);
+                return false;
             }
+            return true;
+        }
+    }
 
-            destroyOptions(new List<List<OptionBehaviour>>{
-                torMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                impostorMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                neutralMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                crewmateMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                modifierMenu.GetComponentsInChildren<OptionBehaviour>().ToList()
-            });
-
-            List<OptionBehaviour> torOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> impostorOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> neutralOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> crewmateOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> modifierOptions = new List<OptionBehaviour>();
-
-
-            List<Transform> menus = new List<Transform>() { torMenu.transform, impostorMenu.transform, neutralMenu.transform, crewmateMenu.transform, modifierMenu.transform };
-            List<List<OptionBehaviour>> optionBehaviours = new List<List<OptionBehaviour>>() { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions };
-
-            for (int i = 0; i < CustomOption.options.Count; i++) {
-                CustomOption option = CustomOption.options[i];
-                if ((int)option.type > 4) continue;
-                if (option.optionBehaviour == null) {
-                    StringOption stringOption = UnityEngine.Object.Instantiate(template, menus[(int)option.type]);
-                    optionBehaviours[(int)option.type].Add(stringOption);
-                    stringOption.OnValueChanged = new Action<OptionBehaviour>((o) => { });
-                    stringOption.TitleText.text = option.name;
-                    stringOption.Value = stringOption.oldValue = option.selection;
-                    stringOption.ValueText.text = option.selections[option.selection].ToString();
+    [HarmonyPatch(typeof(LobbyViewSettingsPane), nameof(LobbyViewSettingsPane.ChangeTab))]
+    class LobbyViewSettingsPaneChangeTabPatch {
+        public static void Postfix(LobbyViewSettingsPane __instance, StringNames category) {
+            int tabNum = (int)category;
 
-                    option.optionBehaviour = stringOption;
-                }
-                option.optionBehaviour.gameObject.SetActive(true);
+            foreach (var pbutton in LobbyViewSettingsPatch.currentButtons) {
+                pbutton.SelectButton(false);
             }
+            if (tabNum > 20) // StringNames are in the range of 3000+ 
+                return;
+            __instance.taskTabButton.SelectButton(false);
 
-            setOptions(
-                new List<GameOptionsMenu> { torMenu, impostorMenu, neutralMenu, crewmateMenu, modifierMenu },
-                new List<List<OptionBehaviour>> { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions },
-                new List<GameObject> { torSettings, impostorSettings, neutralSettings, crewmateSettings, modifierSettings }
-            );
+            if (tabNum > 2) {
+                tabNum -= 3;
+                //GameOptionsMenuStartPatch.currentTabs[tabNum].SetActive(true);
+                LobbyViewSettingsPatch.currentButtons[tabNum].SelectButton(true);
+                LobbyViewSettingsPatch.drawTab(__instance, LobbyViewSettingsPatch.currentButtonTypes[tabNum]);
+            }
+        }
+    }
 
-            adaptTaskCount(__instance);
+    [HarmonyPatch(typeof(LobbyViewSettingsPane), nameof(LobbyViewSettingsPane.Update))]
+    class LobbyViewSettingsPaneUpdatePatch {
+        public static void Postfix(LobbyViewSettingsPane __instance) {
+            if (LobbyViewSettingsPatch.currentButtons.Count == 0) {
+                LobbyViewSettingsPatch.gameModeChangedFlag = true;
+                LobbyViewSettingsPatch.Postfix(__instance);
+                
+            }
         }
+    }
+
 
-        private static void createGuesserTabs(GameOptionsMenu __instance) {
-            bool isReturn = setNames(
-                new Dictionary<string, string>() {
-                    ["TORSettings"] = "The Other Roles Settings",
-                    ["GuesserSettings"] = "Guesser Mode Settings",
-                    ["ImpostorSettings"] = "Impostor Roles Settings",
-                    ["NeutralSettings"] = "Neutral Roles Settings",
-                    ["CrewmateSettings"] = "Crewmate Roles Settings",
-                    ["ModifierSettings"] = "Modifier Settings"
-                });
-
-            if (isReturn) return;
-
-            // Setup TOR tab
-            var template = UnityEngine.Object.FindObjectsOfType<StringOption>().FirstOrDefault();
-            if (template == null) return;
-            var gameSettings = GameObject.Find("Game Settings");
-            var gameSettingMenu = UnityEngine.Object.FindObjectsOfType<GameSettingMenu>().FirstOrDefault();
-
-            var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var torMenu = getMenu(torSettings, "TORSettings");
-
-            var guesserSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var guesserMenu = getMenu(guesserSettings, "GuesserSettings");
-
-            var impostorSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var impostorMenu = getMenu(impostorSettings, "ImpostorSettings");
-
-            var neutralSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var neutralMenu = getMenu(neutralSettings, "NeutralSettings");
-
-            var crewmateSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var crewmateMenu = getMenu(crewmateSettings, "CrewmateSettings");
-
-            var modifierSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var modifierMenu = getMenu(modifierSettings, "ModifierSettings");
-
-            var roleTab = GameObject.Find("RoleTab");
-            var gameTab = GameObject.Find("GameTab");
-
-            var torTab = UnityEngine.Object.Instantiate(roleTab, gameTab.transform.parent);
-            var torTabHighlight = getTabHighlight(torTab, "TheOtherRolesTab", "TheOtherRoles.Resources.TabIcon.png");
-
-            var guesserTab = UnityEngine.Object.Instantiate(roleTab, torTab.transform);
-            var guesserTabHighlight = getTabHighlight(guesserTab, "GuesserTab", "TheOtherRoles.Resources.TabIconGuesserSettings.png");
-
-            var impostorTab = UnityEngine.Object.Instantiate(roleTab, guesserTab.transform);
-            var impostorTabHighlight = getTabHighlight(impostorTab, "ImpostorTab", "TheOtherRoles.Resources.TabIconImpostor.png");
-
-            var neutralTab = UnityEngine.Object.Instantiate(roleTab, impostorTab.transform);
-            var neutralTabHighlight = getTabHighlight(neutralTab, "NeutralTab", "TheOtherRoles.Resources.TabIconNeutral.png");
-
-            var crewmateTab = UnityEngine.Object.Instantiate(roleTab, neutralTab.transform);
-            var crewmateTabHighlight = getTabHighlight(crewmateTab, "CrewmateTab", "TheOtherRoles.Resources.TabIconCrewmate.png");
-
-            var modifierTab = UnityEngine.Object.Instantiate(roleTab, crewmateTab.transform);
-            var modifierTabHighlight = getTabHighlight(modifierTab, "ModifierTab", "TheOtherRoles.Resources.TabIconModifier.png");
-
-            roleTab.active = false;
-            // Position of Tab Icons
-            gameTab.transform.position += Vector3.left * 3f;
-            torTab.transform.position += Vector3.left * 3f;
-            guesserTab.transform.localPosition = Vector3.right * 1f;
-            impostorTab.transform.localPosition = Vector3.right * 1f;
-            neutralTab.transform.localPosition = Vector3.right * 1f;
-            crewmateTab.transform.localPosition = Vector3.right * 1f;
-            modifierTab.transform.localPosition = Vector3.right * 1f;
-
-            var tabs = new GameObject[] { gameTab, torTab, impostorTab, neutralTab, crewmateTab, modifierTab, guesserTab };
-            var settingsHighlightMap = new Dictionary<GameObject, SpriteRenderer> {
-                [gameSettingMenu.RegularGameSettings] = gameSettingMenu.GameSettingsHightlight,
-                [torSettings.gameObject] = torTabHighlight,
-                [impostorSettings.gameObject] = impostorTabHighlight,
-                [neutralSettings.gameObject] = neutralTabHighlight,
-                [crewmateSettings.gameObject] = crewmateTabHighlight,
-                [modifierSettings.gameObject] = modifierTabHighlight,
-                [guesserSettings.gameObject] = guesserTabHighlight
-            };
-            for (int i = 0; i < tabs.Length; i++) {               
-                var button = tabs[i].GetComponentInChildren<PassiveButton>();
-                if (button == null) continue;
-                int copiedIndex = i;
-                button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
-                button.OnClick.AddListener((System.Action)(() => {
-                    setListener(settingsHighlightMap, copiedIndex);
+    [HarmonyPatch(typeof(LobbyViewSettingsPane), nameof(LobbyViewSettingsPane.Awake))]
+    class LobbyViewSettingsPatch{
+        public static List<PassiveButton> currentButtons = new();
+        public static List<CustomOptionType> currentButtonTypes = new();
+        public static bool gameModeChangedFlag = false;
+
+        public static void createCustomButton(LobbyViewSettingsPane __instance, int targetMenu, string buttonName, string buttonText, CustomOptionType optionType) {
+            buttonName = "View" + buttonName;
+            var buttonTemplate = GameObject.Find("OverviewTab");
+            var torSettingsButton = GameObject.Find(buttonName);
+            if (torSettingsButton == null) {
+                torSettingsButton = GameObject.Instantiate(buttonTemplate, buttonTemplate.transform.parent);
+                torSettingsButton.transform.localPosition += Vector3.right * 1.75f * (targetMenu - 2);
+                torSettingsButton.name = buttonName;
+                __instance.StartCoroutine(Effects.Lerp(2f, new Action<float>(p => { torSettingsButton.transform.FindChild("FontPlacer").GetComponentInChildren<TextMeshPro>().text = buttonText; })));
+                var torSettingsPassiveButton = torSettingsButton.GetComponent<PassiveButton>();
+                torSettingsPassiveButton.OnClick.RemoveAllListeners();
+                torSettingsPassiveButton.OnClick.AddListener((System.Action)(() => {
+                    __instance.ChangeTab((StringNames)targetMenu);
                 }));
+                torSettingsPassiveButton.OnMouseOut.RemoveAllListeners();
+                torSettingsPassiveButton.OnMouseOver.RemoveAllListeners();
+                torSettingsPassiveButton.SelectButton(false);
+                currentButtons.Add(torSettingsPassiveButton);
+                currentButtonTypes.Add(optionType);
             }
+        }
 
-            destroyOptions(new List<List<OptionBehaviour>>{
-                torMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                guesserMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                impostorMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                neutralMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                crewmateMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-                modifierMenu.GetComponentsInChildren<OptionBehaviour>().ToList()
-            });
-
-            List<OptionBehaviour> torOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> guesserOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> impostorOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> neutralOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> crewmateOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> modifierOptions = new List<OptionBehaviour>();
-
-
-            List<Transform> menus = new List<Transform>() { torMenu.transform, impostorMenu.transform, neutralMenu.transform, crewmateMenu.transform, modifierMenu.transform, guesserMenu.transform };
-            List<List<OptionBehaviour>> optionBehaviours = new List<List<OptionBehaviour>>() { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions, guesserOptions };
-            List<int> exludedIds = new List<int> { 310, 311, 312, 313, 314, 315, 316, 317, 318 };
-
-            for (int i = 0; i < CustomOption.options.Count; i++) {
-                CustomOption option = CustomOption.options[i];
-                if (exludedIds.Contains(option.id)) continue;
-                if ((int)option.type > 5) continue;
-                if (option.optionBehaviour == null) {
-                    StringOption stringOption = UnityEngine.Object.Instantiate(template, menus[(int)option.type]);
-                    optionBehaviours[(int)option.type].Add(stringOption);
-                    stringOption.OnValueChanged = new Action<OptionBehaviour>((o) => { });
-                    stringOption.TitleText.text = option.name;
-                    stringOption.Value = stringOption.oldValue = option.selection;
-                    stringOption.ValueText.text = option.selections[option.selection].ToString();
+        public static void Postfix(LobbyViewSettingsPane __instance) {
+            currentButtons.ForEach(x => x?.Destroy());
+            currentButtons.Clear();
+            currentButtonTypes.Clear();
 
-                    option.optionBehaviour = stringOption;
-                }
-                option.optionBehaviour.gameObject.SetActive(true);
-            }
+            removeVanillaTabs(__instance);
 
-            setOptions(
-                new List<GameOptionsMenu> { torMenu, impostorMenu, neutralMenu, crewmateMenu, modifierMenu, guesserMenu }, 
-                new List<List<OptionBehaviour>> { torOptions, impostorOptions, neutralOptions, crewmateOptions, modifierOptions, guesserOptions }, 
-                new List<GameObject> { torSettings, impostorSettings, neutralSettings, crewmateSettings, modifierSettings, guesserSettings }
-            );
+            createSettingTabs(__instance);
 
-            adaptTaskCount(__instance);
         }
 
-        private static void createHideNSeekTabs(GameOptionsMenu __instance) {
-            bool isReturn = setNames(
-                new Dictionary<string, string>(){ 
-                    ["TORSettings"] = "The Other Roles Settings", 
-                    ["HideNSeekSettings"] = "Hide 'N Seek Settings" 
-                });
-
-            if (isReturn) return;
-
-            // Setup TOR tab
-            var template = UnityEngine.Object.FindObjectsOfType<StringOption>().FirstOrDefault();
-            if (template == null) return;
-            var gameSettings = GameObject.Find("Game Settings");
-            var gameSettingMenu = UnityEngine.Object.FindObjectsOfType<GameSettingMenu>().FirstOrDefault();
-
-            var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var torMenu = getMenu(torSettings, "TORSettings");
-
-            var hideNSeekSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var hideNSeekMenu = getMenu(hideNSeekSettings, "HideNSeekSettings");
-
-            var roleTab = GameObject.Find("RoleTab");
-            var gameTab = GameObject.Find("GameTab");
-
-            var torTab = UnityEngine.Object.Instantiate(roleTab, gameTab.transform.parent);
-            var torTabHighlight = getTabHighlight(torTab, "TheOtherRolesTab", "TheOtherRoles.Resources.TabIconHideNSeekSettings.png");
-
-            var hideNSeekTab = UnityEngine.Object.Instantiate(roleTab, torTab.transform);
-            var hideNSeekTabHighlight = getTabHighlight(hideNSeekTab, "HideNSeekTab", "TheOtherRoles.Resources.TabIconHideNSeekRoles.png");
-
-            roleTab.active = false;
-            gameTab.active = false;
-
-            // Position of Tab Icons
-            torTab.transform.position += Vector3.left * 3f;
-            hideNSeekTab.transform.position += Vector3.right * 1f;
-
-            var tabs = new GameObject[] { torTab, hideNSeekTab};
-            var settingsHighlightMap = new Dictionary<GameObject, SpriteRenderer> { 
-                [torSettings.gameObject] = torTabHighlight,
-                [hideNSeekSettings.gameObject] = hideNSeekTabHighlight
-            };
-            for (int i = 0; i < tabs.Length; i++) {
-                var button = tabs[i].GetComponentInChildren<PassiveButton>();
-                if (button == null) continue;
-                int copiedIndex = i;
-                button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
-                button.OnClick.AddListener((System.Action)(() => {
-                    setListener(settingsHighlightMap, copiedIndex);                    
-                }));
+        public static void removeVanillaTabs(LobbyViewSettingsPane __instance) {
+            GameObject.Find("RolesTabs")?.Destroy();
+            var overview = GameObject.Find("OverviewTab");
+            if (!gameModeChangedFlag) {
+                overview.transform.localScale = new Vector3(0.5f * overview.transform.localScale.x, overview.transform.localScale.y, overview.transform.localScale.z);
+                overview.transform.localPosition += new Vector3(-1.2f, 0f, 0f);
+                
             }
+            overview.transform.Find("FontPlacer").transform.localScale = new Vector3(1.35f, 1f, 1f);
+            overview.transform.Find("FontPlacer").transform.localPosition = new Vector3(-0.6f, -0.1f, 0f);
+            gameModeChangedFlag = false;
+        }
 
-            destroyOptions(new List<List<OptionBehaviour>>{ 
-                torMenu.GetComponentsInChildren<OptionBehaviour>().ToList(), 
-                hideNSeekMenu.GetComponentsInChildren<OptionBehaviour>().ToList() 
-            });
-
-            List<OptionBehaviour> torOptions = new List<OptionBehaviour>();
-            List<OptionBehaviour> hideNSeekOptions = new List<OptionBehaviour>();
-
-            List<Transform> menus = new List<Transform>() { torMenu.transform, hideNSeekMenu.transform};
-            List<List<OptionBehaviour>> optionBehaviours = new List<List<OptionBehaviour>>() { torOptions, hideNSeekOptions };
-
-            for (int i = 0; i < CustomOption.options.Count; i++) {
-                CustomOption option = CustomOption.options[i];
-                if (option.type != CustomOptionType.HideNSeekMain && option.type != CustomOptionType.HideNSeekRoles) continue;
-                if (option.optionBehaviour == null) {
-                    int index = (int)option.type - 6;
-                    StringOption stringOption = UnityEngine.Object.Instantiate(template, menus[index]);
-                    optionBehaviours[index].Add(stringOption);
-                    stringOption.OnValueChanged = new Action<OptionBehaviour>((o) => { });
-                    stringOption.TitleText.text = option.name;
-                    stringOption.Value = stringOption.oldValue = option.selection;
-                    stringOption.ValueText.text = option.selections[option.selection].ToString();
+        public static void drawTab(LobbyViewSettingsPane __instance, CustomOptionType optionType) {
+
+            var relevantOptions = options.Where(x => x.type == optionType || x.type == CustomOption.CustomOptionType.Guesser && optionType == CustomOptionType.General).ToList();
+           
+            if ((int)optionType == 99) {
+                // Create 4 Groups with Role settings only
+                relevantOptions.Clear();
+                relevantOptions.AddRange(options.Where(x => x.type == CustomOptionType.Impostor && x.isHeader));
+                relevantOptions.AddRange(options.Where(x => x.type == CustomOptionType.Neutral && x.isHeader));
+                relevantOptions.AddRange(options.Where(x => x.type == CustomOptionType.Crewmate && x.isHeader));
+                relevantOptions.AddRange(options.Where(x => x.type == CustomOptionType.Modifier && x.isHeader));
+                foreach (var option in options) {
+                    if (option.parent != null && option.parent.getSelection() > 0) {
+                        if (option.id == 103) //Deputy
+                            relevantOptions.Insert(relevantOptions.IndexOf(CustomOptionHolder.sheriffSpawnRate) + 1, option);
+                        else if (option.id == 224) //Sidekick
+                            relevantOptions.Insert(relevantOptions.IndexOf(CustomOptionHolder.jackalSpawnRate) + 1, option);
+                        else if (option.id == 358) //Prosecutor
+                            relevantOptions.Insert(relevantOptions.IndexOf(CustomOptionHolder.lawyerSpawnRate) + 1, option);
+                    }
+                }
+            }
+
+            if (TORMapOptions.gameMode == CustomGamemodes.Guesser) // Exclude guesser options in neutral mode
+                relevantOptions = relevantOptions.Where(x => !(new List<int> { 310, 311, 312, 313, 314, 315, 316, 317, 318 }).Contains(x.id)).ToList();
+
+            for (int j = 0; j < __instance.settingsInfo.Count; j++) {
+                __instance.settingsInfo[j].gameObject.Destroy();
+            }
+            __instance.settingsInfo.Clear();
+
+            float num = 1.44f;
+            int i = 0;
+            int singles = 0;
+            int headers = 0;
+            int lines = 0;
+            var curType = CustomOptionType.Modifier;
+
+            foreach (var option in relevantOptions) {
+                if (option.isHeader && (int)optionType != 99 || (int)optionType == 99 && curType != option.type) {
+                    curType = option.type;
+                    if (i != 0) num -= 0.59f;
+                    if (i % 2 != 0) singles++;
+                    headers++; // for header
+                    CategoryHeaderMasked categoryHeaderMasked = UnityEngine.Object.Instantiate<CategoryHeaderMasked>(__instance.categoryHeaderOrigin);
+                    categoryHeaderMasked.SetHeader(StringNames.ImpostorsCategory, 61);
+                    categoryHeaderMasked.Title.text = option.heading != "" ? option.heading : option.name;
+                    if ((int)optionType == 99)
+                        categoryHeaderMasked.Title.text = new Dictionary<CustomOptionType, string>() { { CustomOptionType.Impostor, "Impostor Roles" }, { CustomOptionType.Neutral, "Neutral Roles" },
+                            { CustomOptionType.Crewmate, "Crewmate Roles" }, { CustomOptionType.Modifier, "Modifiers" } }[curType];
+                    categoryHeaderMasked.Title.outlineColor = Color.white;
+                    categoryHeaderMasked.Title.outlineWidth = 0.2f;
+                    categoryHeaderMasked.transform.SetParent(__instance.settingsContainer);
+                    categoryHeaderMasked.transform.localScale = Vector3.one;
+                    categoryHeaderMasked.transform.localPosition = new Vector3(-9.77f, num, -2f);
+                    __instance.settingsInfo.Add(categoryHeaderMasked.gameObject);
+                    num -= 0.85f;
+                    i = 0;
+                }
 
-                    option.optionBehaviour = stringOption;
+                ViewSettingsInfoPanel viewSettingsInfoPanel = UnityEngine.Object.Instantiate<ViewSettingsInfoPanel>(__instance.infoPanelOrigin);
+                viewSettingsInfoPanel.transform.SetParent(__instance.settingsContainer);
+                viewSettingsInfoPanel.transform.localScale = Vector3.one;
+                float num2;
+                if (i % 2 == 0) {
+                    lines++;
+                    num2 = -8.95f;
+                    if (i > 0) {
+                        num -= 0.59f;
+                    }
+                } else {
+                    num2 = -3f;
                 }
-                option.optionBehaviour.gameObject.SetActive(true);
+                viewSettingsInfoPanel.transform.localPosition = new Vector3(num2, num, -2f);
+                int value = option.getSelection();
+                viewSettingsInfoPanel.SetInfo(StringNames.ImpostorsCategory, option.selections[value].ToString(), 61);
+                viewSettingsInfoPanel.titleText.text = option.name;
+                if (option.isHeader && (int)optionType != 99 && option.heading == "" && (option.type == CustomOptionType.Neutral || option.type == CustomOptionType.Crewmate || option.type == CustomOptionType.Impostor || option.type == CustomOptionType.Modifier)) {
+                    viewSettingsInfoPanel.titleText.text = "Spawn Chance";
+                }
+                if ((int)optionType == 99) {
+                    viewSettingsInfoPanel.titleText.outlineColor = Color.white;
+                    viewSettingsInfoPanel.titleText.outlineWidth = 0.2f;
+                    if (option.type == CustomOptionType.Modifier)
+                        viewSettingsInfoPanel.settingText.text = viewSettingsInfoPanel.settingText.text + GameOptionsDataPatch.buildModifierExtras(option);
+                }
+                __instance.settingsInfo.Add(viewSettingsInfoPanel.gameObject);
+
+                i++;
             }
+            float actual_spacing = (headers * 0.85f + lines * 0.59f) / (headers + lines);
+            __instance.scrollBar.CalculateAndSetYBounds((float)(__instance.settingsInfo.Count + singles * 2 + headers), 2f, 6f, actual_spacing);
 
-            setOptions(
-                new List<GameOptionsMenu>{torMenu, hideNSeekMenu},
-                new List<List<OptionBehaviour>> {torOptions, hideNSeekOptions}, 
-                new List<GameObject> {torSettings, hideNSeekSettings}
-            );
+        }
 
-            torSettings.gameObject.SetActive(true);
-            torTabHighlight.enabled = true;
-            gameSettingMenu.RegularGameSettings.SetActive(false);
-            gameSettingMenu.GameSettingsHightlight.enabled = false;
+        public static void createSettingTabs(LobbyViewSettingsPane __instance) {
+            // Handle different gamemodes and tabs needed therein.
+            int next = 3;
+            if (TORMapOptions.gameMode == CustomGamemodes.Guesser || TORMapOptions.gameMode == CustomGamemodes.Classic) {
+
+                // create TOR settings
+                createCustomButton(__instance, next++, "TORSettings", "TOR Settings", CustomOptionType.General);
+                   // create TOR settings
+                createCustomButton(__instance, next++, "RoleOverview", "Role Overview", (CustomOptionType)99);
+                // IMp
+                createCustomButton(__instance, next++, "ImpostorSettings", "Impostor Roles", CustomOptionType.Impostor);
+
+                // Neutral
+                createCustomButton(__instance, next++, "NeutralSettings", "Neutral Roles", CustomOptionType.Neutral);
+                // Crew
+                createCustomButton(__instance, next++, "CrewmateSettings", "Crewmate Roles", CustomOptionType.Crewmate);
+                // Modifier
+                createCustomButton(__instance, next++, "ModifierSettings", "Modifiers", CustomOptionType.Modifier);
+
+            } else if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) {
+                // create Main HNS settings
+                createCustomButton(__instance, next++, "HideNSeekMain", "Hide 'N' Seek", CustomOptionType.HideNSeekMain);
+                // create HNS Role settings
+                createCustomButton(__instance, next++, "HideNSeekRoles", "Hide 'N' Seek Roles", CustomOptionType.HideNSeekRoles);
+            } else if (TORMapOptions.gameMode == CustomGamemodes.PropHunt) {
+                createCustomButton(__instance, next++, "PropHunt", "Prop Hunt", CustomOptionType.PropHunt);
+            }
         }
+    }
 
+    [HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.CreateSettings))]
+    class GameOptionsMenuCreateSettingsPatch {
+        public static void Postfix(GameOptionsMenu __instance) {
+            if (__instance.gameObject.name == "GAME SETTINGS TAB")
+                adaptTaskCount(__instance);
+        }
 
-        private static void createPropHuntTabs(GameOptionsMenu __instance) {
-            bool isReturn = setNames(
-                new Dictionary<string, string>() {
-                    ["TORSettings"] = "Prop Hunt Settings"
-                });
+        private static void adaptTaskCount(GameOptionsMenu __instance) {
+            // Adapt task count for main options
+            var commonTasksOption = __instance.Children.ToArray().FirstOrDefault(x => x.TryCast<NumberOption>()?.intOptionName == Int32OptionNames.NumCommonTasks).Cast<NumberOption>();
+            if (commonTasksOption != null) commonTasksOption.ValidRange = new FloatRange(0f, 4f);
+            var shortTasksOption = __instance.Children.ToArray().FirstOrDefault(x => x.TryCast<NumberOption>()?.intOptionName == Int32OptionNames.NumShortTasks).TryCast<NumberOption>();
+            if (shortTasksOption != null) shortTasksOption.ValidRange = new FloatRange(0f, 23f);
+            var longTasksOption = __instance.Children.ToArray().FirstOrDefault(x => x.TryCast<NumberOption>()?.intOptionName == Int32OptionNames.NumLongTasks).TryCast<NumberOption>();
+            if (longTasksOption != null) longTasksOption.ValidRange = new FloatRange(0f, 15f);
+        }
+    }
 
-            if (isReturn) return;
 
-            // Setup TOR tab
-            var template = UnityEngine.Object.FindObjectsOfType<StringOption>().FirstOrDefault();
-            if (template == null) return;
-            var gameSettings = GameObject.Find("Game Settings");
-            var gameSettingMenu = UnityEngine.Object.FindObjectsOfType<GameSettingMenu>().FirstOrDefault();
+    [HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.Start))]
+    class GameOptionsMenuStartPatch {
+        public static List<GameObject> currentTabs = new();
+        public static List<PassiveButton> currentButtons = new();
 
-            var torSettings = UnityEngine.Object.Instantiate(gameSettings, gameSettings.transform.parent);
-            var torMenu = getMenu(torSettings, "TORSettings");
-            var roleTab = GameObject.Find("RoleTab");
-            var gameTab = GameObject.Find("GameTab");
+        public static void Postfix(GameSettingMenu __instance) {
+            currentTabs.ForEach(x => x?.Destroy());
+            currentButtons.ForEach(x => x?.Destroy());
+            currentTabs = new();
+            currentButtons = new();
 
-            var torTab = UnityEngine.Object.Instantiate(roleTab, gameTab.transform.parent);
-            var torTabHighlight = getTabHighlight(torTab, "TheOtherRolesTab", "TheOtherRoles.Resources.TabIconPropHuntSettings.png");
+            if (GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return;
 
-            roleTab.active = false;
-            gameTab.active = false;
+            removeVanillaTabs(__instance);
 
-            // Position of Tab Icons
-            torTab.transform.position += Vector3.left * 3f;
-            
-            var tabs = new GameObject[] {torTab};
-            var settingsHighlightMap = new Dictionary<GameObject, SpriteRenderer> {
-                [torSettings.gameObject] = torTabHighlight
-            };
-            for (int i = 0; i < tabs.Length; i++) {
-                var button = tabs[i].GetComponentInChildren<PassiveButton>();
-                if (button == null) continue;
-                int copiedIndex = i;
-                button.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
-                button.OnClick.AddListener((System.Action)(() => {
-                    setListener(settingsHighlightMap, copiedIndex);
-                }));
-            }
-
-            destroyOptions(new List<List<OptionBehaviour>>{
-                torMenu.GetComponentsInChildren<OptionBehaviour>().ToList(),
-            });
-
-            List<OptionBehaviour> torOptions = new List<OptionBehaviour>();
-
-            List<Transform> menus = new List<Transform>() { torMenu.transform };
-            List<List<OptionBehaviour>> optionBehaviours = new List<List<OptionBehaviour>>() { torOptions };
-
-            for (int i = 0; i < CustomOption.options.Count; i++) {
-                CustomOption option = CustomOption.options[i];
-                if (option.type != CustomOptionType.PropHunt) continue;
-                if (option.optionBehaviour == null) {
-                    int index = 0;
-                    StringOption stringOption = UnityEngine.Object.Instantiate(template, menus[index]);
-                    optionBehaviours[index].Add(stringOption);
-                    stringOption.OnValueChanged = new Action<OptionBehaviour>((o) => { });
-                    stringOption.TitleText.text = option.name;
-                    stringOption.Value = stringOption.oldValue = option.selection;
-                    stringOption.ValueText.text = option.selections[option.selection].ToString();
+            createSettingTabs(__instance);
 
-                    option.optionBehaviour = stringOption;
-                }
-                option.optionBehaviour.gameObject.SetActive(true);
-            }
+            var GOMGameObject = GameObject.Find("GAME SETTINGS TAB");
 
-            setOptions(
-                new List<GameOptionsMenu> { torMenu},
-                new List<List<OptionBehaviour>> { torOptions },
-                new List<GameObject> { torSettings }
-            );
 
-            torSettings.gameObject.SetActive(true);
-            torTabHighlight.enabled = true;
-            gameSettingMenu.RegularGameSettings.SetActive(false);
-            gameSettingMenu.GameSettingsHightlight.enabled = false;
-        }
-        
-        private static void setListener(Dictionary<GameObject, SpriteRenderer> settingsHighlightMap, int index) {
-            foreach (KeyValuePair<GameObject, SpriteRenderer> entry in settingsHighlightMap) {
-                entry.Key.SetActive(false);
-                entry.Value.enabled = false;
-            }
-            settingsHighlightMap.ElementAt(index).Key.SetActive(true);
-            settingsHighlightMap.ElementAt(index).Value.enabled = true;
+            // create copy to clipboard and paste from clipboard buttons.
+            var template = GameObject.Find("PlayerOptionsMenu(Clone)").transform.Find("CloseButton").gameObject;
+            var holderGO = new GameObject("copyPasteButtonParent");
+            var bgrenderer = holderGO.AddComponent<SpriteRenderer>();
+            bgrenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CopyPasteBG.png", 175f);
+            holderGO.transform.SetParent(template.transform.parent, false);
+            holderGO.transform.localPosition = template.transform.localPosition + new Vector3(-8.3f, 0.73f, -2f);
+            holderGO.layer = template.layer;
+            holderGO.SetActive(true);
+            var copyButton = GameObject.Instantiate(template, holderGO.transform);
+            copyButton.transform.localPosition = new Vector3(-0.3f, 0.02f, -2f);
+            var copyButtonPassive = copyButton.GetComponent<PassiveButton>();
+            var copyButtonRenderer = copyButton.GetComponentInChildren<SpriteRenderer>();
+            var copyButtonActiveRenderer = copyButton.transform.GetChild(1).GetComponent<SpriteRenderer>();
+            copyButtonRenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Copy.png", 100f);
+            copyButton.transform.GetChild(1).transform.localPosition = Vector3.zero;
+            copyButtonActiveRenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CopyActive.png", 100f);
+            copyButtonPassive.OnClick.RemoveAllListeners();
+            copyButtonPassive.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
+            copyButtonPassive.OnClick.AddListener((System.Action)(() => {
+                copyToClipboard();
+                copyButtonRenderer.color = Color.green;
+                copyButtonActiveRenderer.color = Color.green;
+                __instance.StartCoroutine(Effects.Lerp(1f, new System.Action<float>((p) => {
+                    if (p > 0.95) {
+                        copyButtonRenderer.color = Color.white;
+                        copyButtonActiveRenderer.color = Color.white;
+                    }
+                })));
+            }));
+            var pasteButton = GameObject.Instantiate(template, holderGO.transform);
+            pasteButton.transform.localPosition = new Vector3(0.3f, 0.02f, -2f);
+            var pasteButtonPassive = pasteButton.GetComponent<PassiveButton>();
+            var pasteButtonRenderer = pasteButton.GetComponentInChildren<SpriteRenderer>();
+            var pasteButtonActiveRenderer = pasteButton.transform.GetChild(1).GetComponent<SpriteRenderer>();
+            pasteButtonRenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Paste.png", 100f);
+            pasteButtonActiveRenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.PasteActive.png", 100f);
+            pasteButtonPassive.OnClick.RemoveAllListeners();
+            pasteButtonPassive.OnClick = new UnityEngine.UI.Button.ButtonClickedEvent();
+            pasteButtonPassive.OnClick.AddListener((System.Action)(() => {
+                pasteButtonRenderer.color = Color.yellow;
+                int success = pasteFromClipboard();
+                pasteButtonRenderer.color = success == 3 ? Color.green : success == 0 ? Color.red : Color.yellow;
+                pasteButtonActiveRenderer.color = success == 3 ? Color.green : success == 0 ? Color.red : Color.yellow;
+                __instance.StartCoroutine(Effects.Lerp(1f, new System.Action<float>((p) => {
+                    if (p > 0.95) {
+                        pasteButtonRenderer.color = Color.white;
+                        pasteButtonActiveRenderer.color = Color.white;
+                    }
+                })));
+            }));
         }
 
-        private static void destroyOptions (List<List<OptionBehaviour>> optionBehavioursList) {
-           foreach (List<OptionBehaviour> optionBehaviours in optionBehavioursList) {
-                foreach (OptionBehaviour option in optionBehaviours)
-                    UnityEngine.Object.Destroy(option.gameObject);
-            }
-        }
+        private static void createSettings(GameOptionsMenu menu, List<CustomOption> options) {
+            float num = 1.5f;
+            foreach (CustomOption option in options) {
+                if (option.isHeader) {
+                    CategoryHeaderMasked categoryHeaderMasked = UnityEngine.Object.Instantiate<CategoryHeaderMasked>(menu.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer);
+                    categoryHeaderMasked.SetHeader(StringNames.ImpostorsCategory, 20);
+                    categoryHeaderMasked.Title.text = option.heading != "" ? option.heading : option.name;
+                    categoryHeaderMasked.Title.outlineColor = Color.white;
+                    categoryHeaderMasked.Title.outlineWidth = 0.2f;
+                    categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
+                    categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, -2f);
+                    num -= 0.63f;
+                }
+                OptionBehaviour optionBehaviour = UnityEngine.Object.Instantiate<StringOption>(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer);
+                optionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
+                optionBehaviour.SetClickMask(menu.ButtonClickMask);
+
+                // "SetUpFromData"
+                SpriteRenderer[] componentsInChildren = optionBehaviour.GetComponentsInChildren<SpriteRenderer>(true);
+                for (int i = 0; i < componentsInChildren.Length; i++) {
+                    componentsInChildren[i].material.SetInt(PlayerMaterial.MaskLayer, 20);
+                }
+                foreach (TextMeshPro textMeshPro in optionBehaviour.GetComponentsInChildren<TextMeshPro>(true)) {
+                    textMeshPro.fontMaterial.SetFloat("_StencilComp", 3f);
+                    textMeshPro.fontMaterial.SetFloat("_Stencil", (float)20);
+                }
 
-        private static bool setNames (Dictionary<string, string> gameObjectNameDisplayNameMap) {
-            foreach (KeyValuePair <string, string> entry in gameObjectNameDisplayNameMap) {
-                if (GameObject.Find(entry.Key) != null) { // Settings setup has already been performed, fixing the title of the tab and returning
-                    GameObject.Find(entry.Key).transform.FindChild("GameGroup").FindChild("Text").GetComponent<TMPro.TextMeshPro>().SetText(entry.Value);
-                    return true;
+                var stringOption = optionBehaviour as StringOption;
+                stringOption.OnValueChanged = new Action<OptionBehaviour>((o) => { });
+                stringOption.TitleText.text = option.name;
+                if (option.isHeader && option.heading == "" && (option.type == CustomOptionType.Neutral || option.type == CustomOptionType.Crewmate || option.type == CustomOptionType.Impostor || option.type == CustomOptionType.Modifier)) {
+                    stringOption.TitleText.text = "Spawn Chance";
                 }
+                if (stringOption.TitleText.text.Length > 25)
+                    stringOption.TitleText.fontSize = 2.2f;
+                if (stringOption.TitleText.text.Length > 40)
+                    stringOption.TitleText.fontSize = 2f;
+                stringOption.Value = stringOption.oldValue = option.selection;
+                stringOption.ValueText.text = option.selections[option.selection].ToString();
+                option.optionBehaviour = stringOption;
+
+                menu.Children.Add(optionBehaviour);
+                num -= 0.45f;
+                menu.scrollBar.SetYBoundsMax(-num - 1.65f);
             }
 
-            return false;
-        }
-
-        private static GameOptionsMenu getMenu(GameObject setting, string settingName) {
-            var menu = setting.transform.FindChild("GameGroup").FindChild("SliderInner").GetComponent<GameOptionsMenu>();
-            setting.name = settingName;
-
-            return menu;
+            for (int i = 0; i < menu.Children.Count; i++) {
+                OptionBehaviour optionBehaviour = menu.Children[i];
+                if (AmongUsClient.Instance && !AmongUsClient.Instance.AmHost) {
+                    optionBehaviour.SetAsPlayer();
+                }
+            }
         }
 
-        private static SpriteRenderer getTabHighlight (GameObject tab, string tabName, string tabSpritePath) {
-            var tabHighlight = tab.transform.FindChild("Hat Button").FindChild("Tab Background").GetComponent<SpriteRenderer>();
-            tab.transform.FindChild("Hat Button").FindChild("Icon").GetComponent<SpriteRenderer>().sprite = Helpers.loadSpriteFromResources(tabSpritePath, 100f);
-            tab.name = "tabName";
-
-            return tabHighlight;
+        private static void removeVanillaTabs(GameSettingMenu __instance) {
+            GameObject.Find("What Is This?")?.Destroy();
+            GameObject.Find("GamePresetButton")?.Destroy();
+            GameObject.Find("RoleSettingsButton")?.Destroy();
+            __instance.ChangeTab(1, false);
         }
 
-        private static void setOptions (List<GameOptionsMenu> menus, List<List<OptionBehaviour>> options, List<GameObject> settings) {
-            if (!(menus.Count == options.Count && options.Count == settings.Count)) {
-                TheOtherRolesPlugin.Logger.LogError("List counts are not equal");
-                return;
+        public static void createCustomButton(GameSettingMenu __instance, int targetMenu, string buttonName, string buttonText) {
+            var leftPanel = GameObject.Find("LeftPanel");
+            var buttonTemplate = GameObject.Find("GameSettingsButton");
+            if (targetMenu == 3) {
+                buttonTemplate.transform.localPosition -= Vector3.up * 0.85f;
+                buttonTemplate.transform.localScale *= Vector2.one * 0.75f;
             }
-            for (int i = 0; i < menus.Count; i++) {
-                menus[i].Children = options[i].ToArray();
-                settings[i].gameObject.SetActive(false);
+            var torSettingsButton = GameObject.Find(buttonName);
+            if (torSettingsButton == null) {
+                torSettingsButton = GameObject.Instantiate(buttonTemplate, leftPanel.transform);
+                torSettingsButton.transform.localPosition += Vector3.up * 0.5f * (targetMenu - 2);
+                torSettingsButton.name = buttonName;
+                __instance.StartCoroutine(Effects.Lerp(2f, new Action<float>(p => { torSettingsButton.transform.FindChild("FontPlacer").GetComponentInChildren<TextMeshPro>().text = buttonText; })));
+                var torSettingsPassiveButton = torSettingsButton.GetComponent<PassiveButton>();
+                torSettingsPassiveButton.OnClick.RemoveAllListeners();
+                torSettingsPassiveButton.OnClick.AddListener((System.Action)(() => {
+                    __instance.ChangeTab(targetMenu, false);
+                }));
+                torSettingsPassiveButton.OnMouseOut.RemoveAllListeners();
+                torSettingsPassiveButton.OnMouseOver.RemoveAllListeners();
+                torSettingsPassiveButton.SelectButton(false);
+                currentButtons.Add(torSettingsPassiveButton);
             }
         }
 
-        private static void adaptTaskCount(GameOptionsMenu __instance) {
-            // Adapt task count for main options
-            var commonTasksOption = __instance.Children.FirstOrDefault(x => x.name == "NumCommonTasks").TryCast<NumberOption>();
-            if (commonTasksOption != null) commonTasksOption.ValidRange = new FloatRange(0f, 4f);
+        public static void createGameOptionsMenu(GameSettingMenu __instance, CustomOptionType optionType, string settingName) {
+            var tabTemplate = GameObject.Find("GAME SETTINGS TAB");
+            currentTabs.RemoveAll(x => x == null);
 
-            var shortTasksOption = __instance.Children.FirstOrDefault(x => x.name == "NumShortTasks").TryCast<NumberOption>();
-            if (shortTasksOption != null) shortTasksOption.ValidRange = new FloatRange(0f, 23f);
+            var torSettingsTab = GameObject.Instantiate(tabTemplate, tabTemplate.transform.parent);
+            torSettingsTab.name = settingName;
+                
+            var torSettingsGOM = torSettingsTab.GetComponent<GameOptionsMenu>();
+            foreach (var child in torSettingsGOM.Children) {
+                child.Destroy();
+            }
+            torSettingsGOM.scrollBar.transform.FindChild("SliderInner").DestroyChildren();
+            torSettingsGOM.Children.Clear();
+            var relevantOptions = options.Where(x => x.type == optionType).ToList();
+            if (TORMapOptions.gameMode == CustomGamemodes.Guesser) // Exclude guesser options in neutral mode
+                relevantOptions = relevantOptions.Where(x => !(new List<int> { 310, 311, 312, 313, 314, 315, 316, 317, 318 }).Contains(x.id)).ToList();
+            createSettings(torSettingsGOM, relevantOptions);
+
+            currentTabs.Add(torSettingsTab);
+            torSettingsTab.SetActive(false);
+        }
 
-            var longTasksOption = __instance.Children.FirstOrDefault(x => x.name == "NumLongTasks").TryCast<NumberOption>();
-            if (longTasksOption != null) longTasksOption.ValidRange = new FloatRange(0f, 15f);
+        private static void createSettingTabs(GameSettingMenu __instance) {
+            // Handle different gamemodes and tabs needed therein.
+            int next = 3;
+            if (TORMapOptions.gameMode == CustomGamemodes.Guesser || TORMapOptions.gameMode == CustomGamemodes.Classic) {
+
+                // create TOR settings
+                createCustomButton(__instance, next++, "TORSettings", "TOR Settings");
+                createGameOptionsMenu(__instance, CustomOptionType.General, "TORSettings");
+                // Guesser if applicable
+                if (TORMapOptions.gameMode == CustomGamemodes.Guesser) {
+                    createCustomButton(__instance, next++, "GuesserSettings", "Guesser Settings");
+                    createGameOptionsMenu(__instance, CustomOptionType.Guesser, "GuesserSettings");
+                }
+                // IMp
+                createCustomButton(__instance, next++, "ImpostorSettings", "Impostor Roles");
+                createGameOptionsMenu(__instance, CustomOptionType.Impostor, "ImpostorSettings");
+
+                // Neutral
+                createCustomButton(__instance, next++, "NeutralSettings", "Neutral Roles");
+                createGameOptionsMenu(__instance, CustomOptionType.Neutral, "NeutralSettings");
+                // Crew
+                createCustomButton(__instance, next++, "CrewmateSettings", "Crewmate Roles");
+                createGameOptionsMenu(__instance, CustomOptionType.Crewmate, "CrewmateSettings");
+                // Modifier
+                createCustomButton(__instance, next++, "ModifierSettings", "Modifiers");
+                createGameOptionsMenu(__instance, CustomOptionType.Modifier, "ModifierSettings");
+
+            } else if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) {
+                // create Main HNS settings
+                createCustomButton(__instance, next++, "HideNSeekMain", "Hide 'N' Seek");
+                createGameOptionsMenu(__instance, CustomOptionType.HideNSeekMain, "HideNSeekMain");
+                // create HNS Role settings
+                createCustomButton(__instance, next++, "HideNSeekRoles", "Hide 'N' Seek Roles");
+                createGameOptionsMenu(__instance, CustomOptionType.HideNSeekRoles, "HideNSeekRoles");
+            } else if (TORMapOptions.gameMode == CustomGamemodes.PropHunt) {
+                createCustomButton(__instance, next++, "PropHunt", "Prop Hunt");
+                createGameOptionsMenu(__instance, CustomOptionType.PropHunt, "PropHunt");
+            }
         }
     }
 
-    [HarmonyPatch(typeof(StringOption), nameof(StringOption.OnEnable))]
+    [HarmonyPatch(typeof(StringOption), nameof(StringOption.Initialize))]
     public class StringOptionEnablePatch {
         public static bool Prefix(StringOption __instance) {
             CustomOption option = CustomOption.options.FirstOrDefault(option => option.optionBehaviour == __instance);
             if (option == null) return true;
 
             __instance.OnValueChanged = new Action<OptionBehaviour>((o) => {});
-            __instance.TitleText.text = option.name;
+            //__instance.TitleText.text = option.name;
             __instance.Value = __instance.oldValue = option.selection;
             __instance.ValueText.text = option.selections[option.selection].ToString();
             
@@ -884,7 +851,7 @@ namespace TheOtherRoles {
     {
         public static void Postfix()
         {
-            CustomOption.ShareOptionSelections();
+            //CustomOption.ShareOptionSelections();
             CustomOption.saveVanillaOptions();
         }
     }
@@ -900,54 +867,6 @@ namespace TheOtherRoles {
     }
 
 
-    [HarmonyPatch(typeof(GameOptionsMenu), nameof(GameOptionsMenu.Update))]
-    class GameOptionsMenuUpdatePatch
-    {
-        private static float timer = 1f;
-        public static void Postfix(GameOptionsMenu __instance) {
-            // Return Menu Update if in normal among us settings 
-            var gameSettingMenu = UnityEngine.Object.FindObjectsOfType<GameSettingMenu>().FirstOrDefault();
-            if (gameSettingMenu.RegularGameSettings.active || gameSettingMenu.RolesSettings.gameObject.active) return;
-
-            __instance.GetComponentInParent<Scroller>().ContentYBounds.max = -0.5F + __instance.Children.Length * 0.55F;
-            timer += Time.deltaTime;
-            if (timer < 0.1f) return;
-            timer = 0f;
-
-            float offset = 2.75f;
-            foreach (CustomOption option in CustomOption.options) {
-                if (GameObject.Find("TORSettings") && option.type != CustomOption.CustomOptionType.General && option.type != CustomOptionType.HideNSeekMain && option.type != CustomOptionType.PropHunt)
-                    continue;
-                if (GameObject.Find("ImpostorSettings") && option.type != CustomOption.CustomOptionType.Impostor)
-                    continue;
-                if (GameObject.Find("NeutralSettings") && option.type != CustomOption.CustomOptionType.Neutral)
-                    continue;
-                if (GameObject.Find("CrewmateSettings") && option.type != CustomOption.CustomOptionType.Crewmate)
-                    continue;
-                if (GameObject.Find("ModifierSettings") && option.type != CustomOption.CustomOptionType.Modifier)
-                    continue;
-                if (GameObject.Find("GuesserSettings") && option.type != CustomOption.CustomOptionType.Guesser)
-                    continue;
-                if (GameObject.Find("HideNSeekSettings") && option.type != CustomOption.CustomOptionType.HideNSeekRoles)
-                    continue;
-                if (option?.optionBehaviour != null && option.optionBehaviour.gameObject != null) {
-                    bool enabled = true;
-                    var parent = option.parent;
-                    while (parent != null && enabled) {
-                        enabled = parent.selection != 0;
-                        parent = parent.parent;
-                    }
-                    option.optionBehaviour.gameObject.SetActive(enabled);
-                    if (enabled) {
-                        offset -= option.isHeader ? 0.75f : 0.5f;
-                        option.optionBehaviour.transform.localPosition = new Vector3(option.optionBehaviour.transform.localPosition.x, offset, option.optionBehaviour.transform.localPosition.z);
-                    }
-                }
-            }
-        }
-    }
-
-
     [HarmonyPatch] 
     class GameOptionsDataPatch
     {
@@ -958,7 +877,7 @@ namespace TheOtherRoles {
             var modifiers = buildOptionsOfType(CustomOption.CustomOptionType.Modifier, true);
             return impRoles + neutralRoles + crewRoles + modifiers;
         }
-        private static string buildModifierExtras(CustomOption customOption) {
+        public static string buildModifierExtras(CustomOption customOption) {
             // find options children with quantity
             var children = CustomOption.options.Where(o => o.parent == customOption);
             var quantity = children.Where(o => o.name.Contains("Quantity")).ToList();
@@ -1156,7 +1075,7 @@ namespace TheOtherRoles {
                     || __instance.PlayerSpeedMod <= 0f || __instance.PlayerSpeedMod > 3f;
         }
 
-        [HarmonyPatch(typeof(StringOption), nameof(StringOption.OnEnable))]
+        [HarmonyPatch(typeof(StringOption), nameof(StringOption.Initialize))]
         [HarmonyPrefix]
         
         public static void Prefix(StringOption __instance)
@@ -1170,7 +1089,7 @@ namespace TheOtherRoles {
             }
         }
 
-        [HarmonyPatch(typeof(StringOption), nameof(StringOption.OnEnable))]
+        [HarmonyPatch(typeof(StringOption), nameof(StringOption.Initialize))]
         [HarmonyPostfix]
         
         public static void Postfix(StringOption __instance)
@@ -1252,39 +1171,27 @@ namespace TheOtherRoles {
             if (Input.GetKeyDown(KeyCode.F1))
                 HudManagerUpdate.ToggleSettings(HudManager.Instance);
             if (TheOtherRolesPlugin.optionsPage >= GameOptionsDataPatch.maxPage) TheOtherRolesPlugin.optionsPage = 0;
-
-            if (page != TheOtherRolesPlugin.optionsPage) {
-                Vector3 position = (Vector3)FastDestroyableSingleton<HudManager>.Instance?.GameSettings?.transform.localPosition;
-                FastDestroyableSingleton<HudManager>.Instance.GameSettings.transform.localPosition = new Vector3(position.x, 2.9f, position.z);
-            }
         }
     }
 
     
-    [HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
-    public class GameSettingsScalePatch {
-        public static void Prefix(HudManager __instance) {
-            if (__instance.GameSettings != null) __instance.GameSettings.fontSize = 1.2f; 
-        }
-    }
-
-
-    // This class is taken and adapted from Town of Us Reactivated, https://github.com/eDonnes124/Town-Of-Us-R/blob/master/source/Patches/CustomOption/Patches.cs, Licensed under GPLv3
+    //This class is taken and adapted from Town of Us Reactivated, https://github.com/eDonnes124/Town-Of-Us-R/blob/master/source/Patches/CustomOption/Patches.cs, Licensed under GPLv3
     [HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))]
     public class HudManagerUpdate {
+        private static GameObject GameSettingsObject;
+        private static TextMeshPro GameSettings;
         public static float
             MinX,/*-5.3F*/
             OriginalY = 2.9F,
             MinY = 2.9F;
 
-
         public static Scroller Scroller;
         private static Vector3 LastPosition;
         private static float lastAspect;
         private static bool setLastPosition = false;
 
         public static void Prefix(HudManager __instance) {
-            if (__instance.GameSettings?.transform == null) return;
+            if (GameSettings?.transform == null) return;
 
             // Sets the MinX position to the left edge of the screen + 0.1 units
             Rect safeArea = Screen.safeArea;
@@ -1301,11 +1208,11 @@ namespace TheOtherRoles {
 
             CreateScroller(__instance);
 
-            Scroller.gameObject.SetActive(__instance.GameSettings.gameObject.activeSelf);
+            Scroller.gameObject.SetActive(GameSettings.gameObject.activeSelf);
 
             if (!Scroller.gameObject.active) return;
 
-            var rows = __instance.GameSettings.text.Count(c => c == '\n');
+            var rows = GameSettings.text.Count(c => c == '\n');
             float LobbyTextRowHeight = 0.06F;
             var maxY = Mathf.Max(MinY, rows * LobbyTextRowHeight + (rows - 38) * LobbyTextRowHeight);
 
@@ -1313,24 +1220,24 @@ namespace TheOtherRoles {
 
             // Prevent scrolling when the player is interacting with a menu
             if (CachedPlayer.LocalPlayer?.PlayerControl.CanMove != true) {
-                __instance.GameSettings.transform.localPosition = LastPosition;
+                GameSettings.transform.localPosition = LastPosition;
 
                 return;
             }
 
-            if (__instance.GameSettings.transform.localPosition.x != MinX ||
-                __instance.GameSettings.transform.localPosition.y < MinY) return;
+            if (GameSettings.transform.localPosition.x != MinX ||
+                GameSettings.transform.localPosition.y < MinY) return;
 
-            LastPosition = __instance.GameSettings.transform.localPosition;
+            LastPosition = GameSettings.transform.localPosition;
         }
 
         private static void CreateScroller(HudManager __instance) {
             if (Scroller != null) return;
 
-            Transform target = __instance.GameSettings.transform;
+            Transform target = GameSettings.transform;
 
             Scroller = new GameObject("SettingsScroller").AddComponent<Scroller>();
-            Scroller.transform.SetParent(__instance.GameSettings.transform.parent);
+            Scroller.transform.SetParent(GameSettings.transform.parent);
             Scroller.gameObject.layer = 5;
 
             Scroller.transform.localScale = Vector3.one;
@@ -1381,9 +1288,7 @@ namespace TheOtherRoles {
         private static TMPro.TextMeshPro[] settingsTMPs = new TMPro.TextMeshPro[4];
         private static GameObject settingsBackground;
         public static void OpenSettings(HudManager __instance) {
-            if (__instance.FullScreen == null || MapBehaviour.Instance && MapBehaviour.Instance.IsOpen
-                /*|| AmongUsClient.Instance.GameState != InnerNet.InnerNetClient.GameStates.Started*/
-                || GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return;
+            if (__instance.FullScreen == null || MapBehaviour.Instance && MapBehaviour.Instance.IsOpen) return;
             settingsBackground = GameObject.Instantiate(__instance.FullScreen.gameObject, __instance.transform);
             settingsBackground.SetActive(true);
             var renderer = settingsBackground.GetComponent<SpriteRenderer>();
@@ -1413,20 +1318,52 @@ namespace TheOtherRoles {
 
         static PassiveButton toggleSettingsButton;
         static GameObject toggleSettingsButtonObject;
+
+        static GameObject toggleZoomButtonObject;
+        static PassiveButton toggleZoomButton;
+
         [HarmonyPostfix]
         public static void Postfix(HudManager __instance) {
+            if (AmongUsClient.Instance.GameState != InnerNet.InnerNetClient.GameStates.Started) return;
             if (!toggleSettingsButton || !toggleSettingsButtonObject) {
                 // add a special button for settings viewing:
                 toggleSettingsButtonObject = GameObject.Instantiate(__instance.MapButton.gameObject, __instance.MapButton.transform.parent);
-                toggleSettingsButtonObject.transform.localPosition = __instance.MapButton.transform.localPosition + new Vector3(0, -0.66f, -500f);
-                SpriteRenderer renderer = toggleSettingsButtonObject.GetComponent<SpriteRenderer>();
-                renderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.CurrentSettingsButton.png", 180f);
+                toggleSettingsButtonObject.transform.localPosition = __instance.MapButton.transform.localPosition + new Vector3(0, -1.25f, -500f);
+                toggleSettingsButtonObject.name = "TOGGLESETTINGSBUTTON";
+                SpriteRenderer renderer = toggleSettingsButtonObject.transform.Find("Inactive").GetComponent<SpriteRenderer>();
+                SpriteRenderer rendererActive = toggleSettingsButtonObject.transform.Find("Active").GetComponent<SpriteRenderer>();
+                toggleSettingsButtonObject.transform.Find("Background").localPosition = Vector3.zero;
+                renderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Settings_Button.png", 100f);
+                rendererActive.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Settings_ButtonActive.png", 100);
                 toggleSettingsButton = toggleSettingsButtonObject.GetComponent<PassiveButton>();
                 toggleSettingsButton.OnClick.RemoveAllListeners();
                 toggleSettingsButton.OnClick.AddListener((Action)(() => ToggleSettings(__instance)));
             }
             toggleSettingsButtonObject.SetActive(__instance.MapButton.gameObject.active && !(MapBehaviour.Instance && MapBehaviour.Instance.IsOpen) && GameOptionsManager.Instance.currentGameOptions.GameMode != GameModes.HideNSeek);
-            toggleSettingsButtonObject.transform.localPosition = __instance.MapButton.transform.localPosition + new Vector3(0, -0.66f, -500f);
+            toggleSettingsButtonObject.transform.localPosition = __instance.MapButton.transform.localPosition + new Vector3(0, -0.8f, -500f);
+
+
+            if (!toggleZoomButton || !toggleZoomButtonObject) {
+                // add a special button for settings viewing:
+                toggleZoomButtonObject = GameObject.Instantiate(__instance.MapButton.gameObject, __instance.MapButton.transform.parent);
+                toggleZoomButtonObject.transform.localPosition = __instance.MapButton.transform.localPosition + new Vector3(0, -1.25f, -500f);
+                toggleZoomButtonObject.name = "TOGGLEZOOMBUTTON";
+                SpriteRenderer tZrenderer = toggleZoomButtonObject.transform.Find("Inactive").GetComponent<SpriteRenderer>();
+                SpriteRenderer tZArenderer = toggleZoomButtonObject.transform.Find("Active").GetComponent<SpriteRenderer>();
+                toggleZoomButtonObject.transform.Find("Background").localPosition = Vector3.zero;
+                tZrenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_Button.png", 100f);
+                tZArenderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Minus_ButtonActive.png", 100);
+                toggleZoomButton = toggleZoomButtonObject.GetComponent<PassiveButton>();
+                toggleZoomButton.OnClick.RemoveAllListeners();
+                toggleZoomButton.OnClick.AddListener((Action)(() => Helpers.toggleZoom()));
+            }
+            var (playerCompleted, playerTotal) = TasksHandler.taskInfo(CachedPlayer.LocalPlayer.Data);
+            int numberOfLeftTasks = playerTotal - playerCompleted;
+            bool zoomButtonActive = !(CachedPlayer.LocalPlayer.PlayerControl == null || !CachedPlayer.LocalPlayer.Data.IsDead || (CachedPlayer.LocalPlayer.Data.Role.IsImpostor && !CustomOptionHolder.deadImpsBlockSabotage.getBool()));
+            zoomButtonActive &= numberOfLeftTasks <= 0 || !CustomOptionHolder.finishTasksBeforeHauntingOrZoomingOut.getBool();
+            toggleZoomButtonObject.SetActive(zoomButtonActive);
+            var posOffset = Helpers.zoomOutStatus ? new Vector3(-1.27f, -7.92f, -52f) : new Vector3(0, -1.6f, -52f);
+            toggleZoomButtonObject.transform.localPosition = HudManager.Instance.MapButton.transform.localPosition + posOffset;
         }
     }
 }
index 3c27bd905fb13807dd6ca401d33b8c442f6592e8..88faa78a798c06e4bf0c111f56ce5ff4a125d020 100644 (file)
@@ -34,7 +34,7 @@ namespace TheOtherRoles.Objects
             public Transform Transform;
             public SpriteRenderer Renderer;
             public PlayerControl Owner;
-            public GameData.PlayerInfo Data;
+            public NetworkedPlayerInfo Data;
             public float Lifetime;
 
             public Footprint() {
index 5d0f09f9e1e4f45c49600d452e0a121510532711..7d2cfaab2ab09652c6d8dd96ee7463e03928bcb1 100644 (file)
@@ -29,7 +29,6 @@ namespace TheOtherRoles.Objects {
 
         public Silhouette(Vector3 p, float duration = 1f, bool visibleForEveryOne = true) {
             if (duration <= 0f) {
-                TheOtherRolesPlugin.Logger.LogMessage("silhouette: permanent!");
                 permanent = true;
             }
             this.visibleForEveryOne = visibleForEveryOne;
@@ -71,7 +70,6 @@ namespace TheOtherRoles.Objects {
                 }
 
                 if (current.timeRemaining < 0 && !current.permanent) {
-                    TheOtherRolesPlugin.Logger.LogMessage($"update: permanent: {current.permanent}, time: {current.timeRemaining}");
                     current.gameObject.SetActive(false);
                     UnityEngine.Object.Destroy(current.gameObject);
                     silhouettes.Remove(current);
index f212c5cf87994ba6e09585d507dd372af8654b48..36b2b6189efc03718af602220524fd3fb638480f 100644 (file)
@@ -22,6 +22,7 @@ namespace TheOtherRoles.Patches
             new("Show Lighter / Darker", () => TORMapOptions.showLighterDarker = TheOtherRolesPlugin.ShowLighterDarker.Value = !TheOtherRolesPlugin.ShowLighterDarker.Value, TheOtherRolesPlugin.ShowLighterDarker.Value),
             new("Enable Sound Effects", () => TORMapOptions.enableSoundEffects = TheOtherRolesPlugin.EnableSoundEffects.Value = !TheOtherRolesPlugin.EnableSoundEffects.Value, TheOtherRolesPlugin.EnableSoundEffects.Value),
             new("Show Vents On Map", () => TORMapOptions.ShowVentsOnMap = TheOtherRolesPlugin.ShowVentsOnMap.Value = !TheOtherRolesPlugin.ShowVentsOnMap.Value, TheOtherRolesPlugin.ShowVentsOnMap.Value),
+            new("Show Chat Notifications", () => TORMapOptions.ShowChatNotifications = TheOtherRolesPlugin.ShowChatNotifications.Value = !TheOtherRolesPlugin.ShowChatNotifications.Value, TheOtherRolesPlugin.ShowChatNotifications.Value),
         };
         
         private static GameObject popUp;
index c9a5fc3fbaab9f349154cd86dde3d0fe12918007..7670cfeeb594ab7e096a0d9faa16fd9e7e9c4e49 100644 (file)
@@ -4,8 +4,8 @@ namespace TheOtherRoles.Patches {
     [HarmonyPatch(typeof(Constants), nameof(Constants.GetBroadcastVersion))]
     public static class ConstantsPatch {
         public static void Postfix(ref int __result) {
-            if (AmongUsClient.Instance.NetworkMode == NetworkModes.OnlineGame)
-                __result += 25;
+            /*if (AmongUsClient.Instance.NetworkMode == NetworkModes.OnlineGame)
+                __result += 25;*/
         }
     }
 }
\ No newline at end of file
index 1f9fbd5e1142257989554d0c3bc61451d5271199..bc252ff5b714433e921c4471c7a0814d46b75820 100644 (file)
@@ -1,4 +1,5 @@
-using HarmonyLib;
+using AmongUs.GameOptions;
+using HarmonyLib;
 using System;
 using System.Collections.Generic;
 using System.Net.Http;
@@ -32,8 +33,9 @@ $@"<size=60%> <color=#FCCE03FF>Special thanks to Smeggy</color></size>";
         {
 
             static void Postfix(PingTracker __instance){
-                __instance.text.alignment = TextAlignmentOptions.TopRight;
+                __instance.text.alignment = TextAlignmentOptions.Top;
                 var position = __instance.GetComponent<AspectPosition>();
+                position.Alignment = AspectPosition.EdgeAlignments.Top;
                 if (AmongUsClient.Instance.GameState == InnerNet.InnerNetClient.GameStates.Started) {
                     string gameModeText = $"";
                     if (HideNSeek.isHideNSeekGM) gameModeText = $"Hide 'N Seek";
@@ -47,11 +49,17 @@ $@"<size=60%> <color=#FCCE03FF>Special thanks to Smeggy</color></size>";
                     if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek) gameModeText = $"Hide 'N Seek";
                     else if (TORMapOptions.gameMode == CustomGamemodes.Guesser) gameModeText = $"Guesser";
                     else if (TORMapOptions.gameMode == CustomGamemodes.PropHunt) gameModeText = $"Prop Hunt";
-                    if (gameModeText != "") gameModeText = Helpers.cs(Color.yellow, gameModeText) + "\n";
+                    if (gameModeText != "") gameModeText = Helpers.cs(Color.yellow, gameModeText);
+
+                    __instance.text.text = $"{fullCredentialsVersion}\n{fullCredentials}\n {__instance.text.text}";
+                    position.DistanceFromEdge = new Vector3( 0f, 0.1f, 0);
 
-                    var host = $"Host: {GameData.Instance?.GetHost()?.PlayerName}";
-                    __instance.text.text = $"{fullCredentialsVersion}\n  {gameModeText + fullCredentials}\n {host}\n {__instance.text.text}";
-                    position.DistanceFromEdge = new Vector3(3.5f, 0.1f, 0);
+                    try {
+                        var GameModeText = GameObject.Find("GameModeText")?.GetComponent<TextMeshPro>();
+                        GameModeText.text = gameModeText == "" ? (GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek ? "Van. HideNSeek" : "Classic" ): gameModeText;
+                        var ModeLabel = GameObject.Find("ModeLabel")?.GetComponentInChildren<TextMeshPro>();
+                        ModeLabel.text = "Game Mode";
+                    } catch { }
                 }
                 position.AdjustPosition();
             }
index 8a1c2fd5778624834f3faf3de0d775be4db4b42c..485c621101d894f001b6acd6efd7931be925a7a3 100644 (file)
@@ -101,11 +101,11 @@ namespace TheOtherRoles.Patches {
 
             notWinners.AddRange(Jackal.formerJackals);
 
-            List<WinningPlayerData> winnersToRemove = new List<WinningPlayerData>();
-            foreach (WinningPlayerData winner in TempData.winners.GetFastEnumerator()) {
+            List<CachedPlayerData> winnersToRemove = new List<CachedPlayerData>();
+            foreach (CachedPlayerData winner in EndGameResult.CachedWinners.GetFastEnumerator()) {
                 if (notWinners.Any(x => x.Data.PlayerName == winner.PlayerName)) winnersToRemove.Add(winner);
             }
-            foreach (var winner in winnersToRemove) TempData.winners.Remove(winner);
+            foreach (var winner in winnersToRemove) EndGameResult.CachedWinners.Remove(winner);
 
             bool jesterWin = Jester.jester != null && gameOverReason == (GameOverReason)CustomGameOverReason.JesterWin;
             bool arsonistWin = Arsonist.arsonist != null && gameOverReason == (GameOverReason)CustomGameOverReason.ArsonistWin;
@@ -119,42 +119,42 @@ namespace TheOtherRoles.Patches {
 
             // Mini lose
             if (miniLose) {
-                TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
-                WinningPlayerData wpd = new WinningPlayerData(Mini.mini.Data);
+                EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
+                CachedPlayerData wpd = new CachedPlayerData(Mini.mini.Data);
                 wpd.IsYou = false; // If "no one is the Mini", it will display the Mini, but also show defeat to everyone
-                TempData.winners.Add(wpd);
+                EndGameResult.CachedWinners.Add(wpd);
                 AdditionalTempData.winCondition = WinCondition.MiniLose;  
             }
 
             // Jester win
             else if (jesterWin) {
-                TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
-                WinningPlayerData wpd = new WinningPlayerData(Jester.jester.Data);
-                TempData.winners.Add(wpd);
+                EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
+                CachedPlayerData wpd = new CachedPlayerData(Jester.jester.Data);
+                EndGameResult.CachedWinners.Add(wpd);
                 AdditionalTempData.winCondition = WinCondition.JesterWin;
             }
 
             // Arsonist win
             else if (arsonistWin) {
-                TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
-                WinningPlayerData wpd = new WinningPlayerData(Arsonist.arsonist.Data);
-                TempData.winners.Add(wpd);
+                EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
+                CachedPlayerData wpd = new CachedPlayerData(Arsonist.arsonist.Data);
+                EndGameResult.CachedWinners.Add(wpd);
                 AdditionalTempData.winCondition = WinCondition.ArsonistWin;
             }
 
             // Vulture win
             else if (vultureWin) {
-                TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
-                WinningPlayerData wpd = new WinningPlayerData(Vulture.vulture.Data);
-                TempData.winners.Add(wpd);
+                EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
+                CachedPlayerData wpd = new CachedPlayerData(Vulture.vulture.Data);
+                EndGameResult.CachedWinners.Add(wpd);
                 AdditionalTempData.winCondition = WinCondition.VultureWin;
             }
 
             // Jester win
             else if (prosecutorWin) {
-                TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
-                WinningPlayerData wpd = new WinningPlayerData(Lawyer.lawyer.Data);
-                TempData.winners.Add(wpd);
+                EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
+                CachedPlayerData wpd = new CachedPlayerData(Lawyer.lawyer.Data);
+                EndGameResult.CachedWinners.Add(wpd);
                 AdditionalTempData.winCondition = WinCondition.ProsecutorWin;
             }
 
@@ -163,23 +163,23 @@ namespace TheOtherRoles.Patches {
                 // Double win for lovers, crewmates also win
                 if (!Lovers.existingWithKiller()) {
                     AdditionalTempData.winCondition = WinCondition.LoversTeamWin;
-                    TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
+                    EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
                     foreach (PlayerControl p in CachedPlayer.AllPlayers) {
                         if (p == null) continue;
                         if (p == Lovers.lover1 || p == Lovers.lover2)
-                            TempData.winners.Add(new WinningPlayerData(p.Data));
+                            EndGameResult.CachedWinners.Add(new CachedPlayerData(p.Data));
                         else if (p == Pursuer.pursuer && !Pursuer.pursuer.Data.IsDead)
-                            TempData.winners.Add(new WinningPlayerData(p.Data));
+                            EndGameResult.CachedWinners.Add(new CachedPlayerData(p.Data));
                         else if (p != Jester.jester && p != Jackal.jackal && p != Sidekick.sidekick && p != Arsonist.arsonist && p != Vulture.vulture && !Jackal.formerJackals.Contains(p) && !p.Data.Role.IsImpostor)
-                            TempData.winners.Add(new WinningPlayerData(p.Data));
+                            EndGameResult.CachedWinners.Add(new CachedPlayerData(p.Data));
                     }
                 }
                 // Lovers solo win
                 else {
                     AdditionalTempData.winCondition = WinCondition.LoversSoloWin;
-                    TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
-                    TempData.winners.Add(new WinningPlayerData(Lovers.lover1.Data));
-                    TempData.winners.Add(new WinningPlayerData(Lovers.lover2.Data));
+                    EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
+                    EndGameResult.CachedWinners.Add(new CachedPlayerData(Lovers.lover1.Data));
+                    EndGameResult.CachedWinners.Add(new CachedPlayerData(Lovers.lover2.Data));
                 }
             }
             
@@ -187,41 +187,41 @@ namespace TheOtherRoles.Patches {
             else if (teamJackalWin) {
                 // Jackal wins if nobody except jackal is alive
                 AdditionalTempData.winCondition = WinCondition.JackalWin;
-                TempData.winners = new Il2CppSystem.Collections.Generic.List<WinningPlayerData>();
-                WinningPlayerData wpd = new WinningPlayerData(Jackal.jackal.Data);
+                EndGameResult.CachedWinners = new Il2CppSystem.Collections.Generic.List<CachedPlayerData>();
+                CachedPlayerData wpd = new CachedPlayerData(Jackal.jackal.Data);
                 wpd.IsImpostor = false; 
-                TempData.winners.Add(wpd);
+                EndGameResult.CachedWinners.Add(wpd);
                 // If there is a sidekick. The sidekick also wins
                 if (Sidekick.sidekick != null) {
-                    WinningPlayerData wpdSidekick = new WinningPlayerData(Sidekick.sidekick.Data);
+                    CachedPlayerData wpdSidekick = new CachedPlayerData(Sidekick.sidekick.Data);
                     wpdSidekick.IsImpostor = false; 
-                    TempData.winners.Add(wpdSidekick);
+                    EndGameResult.CachedWinners.Add(wpdSidekick);
                 }
                 foreach(var player in Jackal.formerJackals) {
-                    WinningPlayerData wpdFormerJackal = new WinningPlayerData(player.Data);
+                    CachedPlayerData wpdFormerJackal = new CachedPlayerData(player.Data);
                     wpdFormerJackal.IsImpostor = false; 
-                    TempData.winners.Add(wpdFormerJackal);
+                    EndGameResult.CachedWinners.Add(wpdFormerJackal);
                 }
             }
 
             // Possible Additional winner: Lawyer
             if (Lawyer.lawyer != null && Lawyer.target != null && (!Lawyer.target.Data.IsDead || Lawyer.target == Jester.jester) && !Pursuer.notAckedExiled && !Lawyer.isProsecutor) {
-                WinningPlayerData winningClient = null;
-                foreach (WinningPlayerData winner in TempData.winners.GetFastEnumerator()) {
+                CachedPlayerData winningClient = null;
+                foreach (CachedPlayerData winner in EndGameResult.CachedWinners.GetFastEnumerator()) {
                     if (winner.PlayerName == Lawyer.target.Data.PlayerName)
                         winningClient = winner;
                 }
                 if (winningClient != null) { // The Lawyer wins if the client is winning (and alive, but if he wasn't the Lawyer shouldn't exist anymore)
-                    if (!TempData.winners.ToArray().Any(x => x.PlayerName == Lawyer.lawyer.Data.PlayerName))
-                        TempData.winners.Add(new WinningPlayerData(Lawyer.lawyer.Data));
+                    if (!EndGameResult.CachedWinners.ToArray().Any(x => x.PlayerName == Lawyer.lawyer.Data.PlayerName))
+                        EndGameResult.CachedWinners.Add(new CachedPlayerData(Lawyer.lawyer.Data));
                     AdditionalTempData.additionalWinConditions.Add(WinCondition.AdditionalLawyerBonusWin); // The Lawyer wins together with the client
                 } 
             }
 
             // Possible Additional winner: Pursuer
-            if (Pursuer.pursuer != null && !Pursuer.pursuer.Data.IsDead && !Pursuer.notAckedExiled && !isPursurerLose && !TempData.winners.ToArray().Any(x => x.IsImpostor)) {
-                if (!TempData.winners.ToArray().Any(x => x.PlayerName == Pursuer.pursuer.Data.PlayerName))
-                    TempData.winners.Add(new WinningPlayerData(Pursuer.pursuer.Data));
+            if (Pursuer.pursuer != null && !Pursuer.pursuer.Data.IsDead && !Pursuer.notAckedExiled && !isPursurerLose && !EndGameResult.CachedWinners.ToArray().Any(x => x.IsImpostor)) {
+                if (!EndGameResult.CachedWinners.ToArray().Any(x => x.PlayerName == Pursuer.pursuer.Data.PlayerName))
+                    EndGameResult.CachedWinners.Add(new CachedPlayerData(Pursuer.pursuer.Data));
                 AdditionalTempData.additionalWinConditions.Add(WinCondition.AdditionalAlivePursuerWin);
             }
 
@@ -242,16 +242,16 @@ namespace TheOtherRoles.Patches {
                 UnityEngine.Object.Destroy(pb.gameObject);
             }
             int num = Mathf.CeilToInt(7.5f);
-            List<WinningPlayerData> list = TempData.winners.ToArray().ToList().OrderBy(delegate(WinningPlayerData b)
+            List<CachedPlayerData> list = EndGameResult.CachedWinners.ToArray().ToList().OrderBy(delegate(CachedPlayerData b)
             {
                 if (!b.IsYou)
                 {
                     return 0;
                 }
                 return -1;
-            }).ToList<WinningPlayerData>();
+            }).ToList<CachedPlayerData>();
             for (int i = 0; i < list.Count; i++) {
-                WinningPlayerData winningPlayerData2 = list[i];
+                CachedPlayerData CachedPlayerData2 = list[i];
                 int num2 = (i % 2 == 0) ? -1 : 1;
                 int num3 = (i + 1) / 2;
                 float num4 = (float)num3 / (float)num;
@@ -262,21 +262,21 @@ namespace TheOtherRoles.Patches {
                 float num7 = Mathf.Lerp(1f, 0.65f, num4) * 0.9f;
                 Vector3 vector = new Vector3(num7, num7, 1f);
                 poolablePlayer.transform.localScale = vector;
-                if (winningPlayerData2.IsDead) {
+                if (CachedPlayerData2.IsDead) {
                     poolablePlayer.SetBodyAsGhost();
                     poolablePlayer.SetDeadFlipX(i % 2 == 0);
                 } else {
                     poolablePlayer.SetFlipX(i % 2 == 0);
                 }
-                poolablePlayer.UpdateFromPlayerOutfit(winningPlayerData2, PlayerMaterial.MaskType.None, winningPlayerData2.IsDead, true);
+                poolablePlayer.UpdateFromPlayerOutfit(CachedPlayerData2.Outfit, PlayerMaterial.MaskType.None, CachedPlayerData2.IsDead, true);
 
                 poolablePlayer.cosmetics.nameText.color = Color.white;
                 poolablePlayer.cosmetics.nameText.transform.localScale = new Vector3(1f / vector.x, 1f / vector.y, 1f / vector.z);
                 poolablePlayer.cosmetics.nameText.transform.localPosition = new Vector3(poolablePlayer.cosmetics.nameText.transform.localPosition.x, poolablePlayer.cosmetics.nameText.transform.localPosition.y, -15f);
-                poolablePlayer.cosmetics.nameText.text = winningPlayerData2.PlayerName;
+                poolablePlayer.cosmetics.nameText.text = CachedPlayerData2.PlayerName;
 
                 foreach(var data in AdditionalTempData.playerRoles) {
-                    if (data.PlayerName != winningPlayerData2.PlayerName) continue;
+                    if (data.PlayerName != CachedPlayerData2.PlayerName) continue;
                     var roles = 
                     poolablePlayer.cosmetics.nameText.text += $"\n{string.Join("\n", data.Roles.Select(x => Helpers.cs(x.color, x.name)))}";
                 }
@@ -495,7 +495,7 @@ namespace TheOtherRoles.Patches {
             if (statistics.TeamImpostorsAlive >= statistics.TotalAlive - statistics.TeamImpostorsAlive && statistics.TeamJackalAlive == 0 && !(statistics.TeamImpostorHasAliveLover && statistics.TeamLoversAlive == 2)) {
                 //__instance.enabled = false;
                 GameOverReason endReason;
-                switch (TempData.LastDeathReason) {
+                switch (GameData.LastDeathReason) {
                     case DeathReason.Exile:
                         endReason = GameOverReason.ImpostorByVote;
                         break;
@@ -550,7 +550,7 @@ namespace TheOtherRoles.Patches {
             GetPlayerCounts();
         }
 
-        private bool isLover(GameData.PlayerInfo p) {
+        private bool isLover(NetworkedPlayerInfo p) {
             return (Lovers.lover1 != null && Lovers.lover1.PlayerId == p.PlayerId) || (Lovers.lover2 != null && Lovers.lover2.PlayerId == p.PlayerId);
         }
 
index 50e1f831bd6ee72e084ffed49d6392822a7277fa..12b1ea2f34745a1628eb27aaa17205694c201cd0 100644 (file)
@@ -13,8 +13,8 @@ namespace TheOtherRoles.Patches {
     [HarmonyPatch(typeof(ExileController), nameof(ExileController.Begin))]
     [HarmonyPriority(Priority.First)]
     class ExileControllerBeginPatch {
-        public static GameData.PlayerInfo lastExiled;
-        public static void Prefix(ExileController __instance, [HarmonyArgument(0)]ref GameData.PlayerInfo exiled, [HarmonyArgument(1)]bool tie) {
+        public static NetworkedPlayerInfo lastExiled;
+        public static void Prefix(ExileController __instance, [HarmonyArgument(0)]ref NetworkedPlayerInfo exiled, [HarmonyArgument(1)]bool tie) {
             lastExiled = exiled;
 
             // Medic shield
@@ -158,7 +158,7 @@ namespace TheOtherRoles.Patches {
             }
         }
 
-        static void WrapUpPostfix(GameData.PlayerInfo exiled) {
+        static void WrapUpPostfix(NetworkedPlayerInfo exiled) {
             // Prosecutor win condition
             if (exiled != null && Lawyer.lawyer != null && Lawyer.target != null && Lawyer.isProsecutor && Lawyer.target.PlayerId == exiled.PlayerId && !Lawyer.lawyer.Data.IsDead)
                 Lawyer.triggerProsecutorWin = true;
index c5eb053389bba74d5a808921c3aad2ffcdf70415..afe8f4b0efb4865ad790021ca0fef09c207591a9 100644 (file)
@@ -24,6 +24,7 @@ namespace TheOtherRoles.Patches {
                 if (CachedPlayer.LocalPlayer != null) {
                     Helpers.shareGameVersion();
                 }
+                GameStartManagerUpdatePatch.sendGamemode = true;
             }
         }
 
@@ -49,6 +50,7 @@ namespace TheOtherRoles.Patches {
             private static bool update = false;
             private static string currentText = "";
             private static GameObject copiedStartButton;
+            public static bool sendGamemode = true;
 
             public static void Prefix(GameStartManager __instance) {
                 if (!GameData.Instance ) return; // No instance
@@ -63,15 +65,12 @@ namespace TheOtherRoles.Patches {
                     Helpers.shareGameVersion();
                 }
 
-                // Check version handshake infos
 
+                // Check version handshake infos
                 bool versionMismatch = false;
                 string message = "";
                 foreach (InnerNet.ClientData client in AmongUsClient.Instance.allClients.ToArray()) {
                     if (client.Character == null) continue;
-                    var dummyComponent = client.Character.GetComponent<DummyBehaviour>();
-                    if (dummyComponent != null && dummyComponent.enabled)
-                        continue;
                     else if (!playerVersions.ContainsKey(client.Id))  {
                         versionMismatch = true;
                         message += $"<color=#FF0000FF>{client.Character.Data.PlayerName} has a different or no version of The Other Roles\n</color>";
@@ -90,39 +89,39 @@ namespace TheOtherRoles.Patches {
                         }
                     }
                 }
-
                 // Display message to the host
                 if (AmongUsClient.Instance.AmHost) {
                     if (versionMismatch) {
-                        __instance.StartButton.color = __instance.startLabelText.color = Palette.DisabledClear;
                         __instance.GameStartText.text = message;
-                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 2;
+                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 5;
+                        __instance.GameStartText.transform.localScale = new Vector3(2f, 2f, 1f);
+                        __instance.GameStartTextParent.SetActive(true);
                     } else {
-                        __instance.StartButton.color = __instance.startLabelText.color = ((__instance.LastPlayerCount >= __instance.MinPlayers) ? Palette.EnabledColor : Palette.DisabledClear);
-                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition;
+                        __instance.GameStartText.transform.localPosition = Vector3.zero;
+                        __instance.GameStartText.transform.localScale = new Vector3(1.2f, 1.2f, 1f);
+                        if (!__instance.GameStartText.text.StartsWith("Starting")) {
+                            __instance.GameStartText.text = String.Empty;
+                            __instance.GameStartTextParent.SetActive(false);
+                        }
                     }
 
                     if (__instance.startState != GameStartManager.StartingStates.Countdown)
                         copiedStartButton?.Destroy();
-
                     // Make starting info available to clients:
                     if (startingTimer <= 0 && __instance.startState == GameStartManager.StartingStates.Countdown) {
                         MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SetGameStarting, Hazel.SendOption.Reliable, -1);
                         AmongUsClient.Instance.FinishRpcImmediately(writer);
                         RPCProcedure.setGameStarting();
-
                         // Activate Stop-Button
                         copiedStartButton = GameObject.Instantiate(__instance.StartButton.gameObject, __instance.StartButton.gameObject.transform.parent);
                         copiedStartButton.transform.localPosition = __instance.StartButton.transform.localPosition;
-                        copiedStartButton.GetComponent<SpriteRenderer>().sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.StopClean.png", 180f);
                         copiedStartButton.SetActive(true);
                         var startButtonText = copiedStartButton.GetComponentInChildren<TMPro.TextMeshPro>();
-                        startButtonText.text = "STOP";
+                        startButtonText.text = "";
                         startButtonText.fontSize *= 0.8f;
                         startButtonText.fontSizeMax = startButtonText.fontSize;
                         startButtonText.gameObject.transform.localPosition = Vector3.zero;
                         PassiveButton startButtonPassiveButton = copiedStartButton.GetComponent<PassiveButton>();
-
                         void StopStartFunc() {
                             __instance.ResetStartState();
                             copiedStartButton.Destroy();
@@ -130,14 +129,13 @@ namespace TheOtherRoles.Patches {
                         }
                         startButtonPassiveButton.OnClick.AddListener((Action)(() => StopStartFunc()));
                         __instance.StartCoroutine(Effects.Lerp(.1f, new System.Action<float>((p) => {
-                            startButtonText.text = "STOP";
+                            startButtonText.text = "";
                         })));
+                        
 
                     }
-                    if (__instance.startState == GameStartManager.StartingStates.Countdown)
-                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 0.6f;
                 }
-
+                
                 // Client update with handshake infos
                 else {
                     if (!playerVersions.ContainsKey(AmongUsClient.Instance.HostId) || TheOtherRolesPlugin.Version.CompareTo(playerVersions[AmongUsClient.Instance.HostId].version) != 0) {
@@ -149,14 +147,21 @@ namespace TheOtherRoles.Patches {
                         }
 
                         __instance.GameStartText.text = $"<color=#FF0000FF>The host has no or a different version of The Other Roles\nYou will be kicked in {Math.Round(10 - kickingTimer)}s</color>";
-                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 2;
+                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 5;
+                        __instance.GameStartText.transform.localScale = new Vector3(2f, 2f, 1f);
+                        __instance.GameStartTextParent.SetActive(true);
                     } else if (versionMismatch) {
                         __instance.GameStartText.text = $"<color=#FF0000FF>Players With Different Versions:\n</color>" + message;
-                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 2;
+                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 5;
+                        __instance.GameStartText.transform.localScale = new Vector3(2f, 2f, 1f);
+                        __instance.GameStartTextParent.SetActive(true);
                     } else {
-                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition;
-                        if (!__instance.GameStartText.text.StartsWith("Starting"))
+                        __instance.GameStartText.transform.localPosition = Vector3.zero;
+                        __instance.GameStartText.transform.localScale = new Vector3(1.2f, 1.2f, 1f);
+                        if (!__instance.GameStartText.text.StartsWith("Starting")) {
                             __instance.GameStartText.text = String.Empty;
+                            __instance.GameStartTextParent.SetActive(false);
+                        }
                     }
 
                     if (!__instance.GameStartText.text.StartsWith("Starting") || !CustomOptionHolder.anyPlayerCanStopStart.getBool())
@@ -166,10 +171,9 @@ namespace TheOtherRoles.Patches {
                         // Activate Stop-Button
                         copiedStartButton = GameObject.Instantiate(__instance.StartButton.gameObject, __instance.StartButton.gameObject.transform.parent);
                         copiedStartButton.transform.localPosition = __instance.StartButton.transform.localPosition;
-                        copiedStartButton.GetComponent<SpriteRenderer>().sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.StopClean.png", 180f);
                         copiedStartButton.SetActive(true);
                         var startButtonText = copiedStartButton.GetComponentInChildren<TMPro.TextMeshPro>();
-                        startButtonText.text = "STOP";
+                        startButtonText.text = "";
                         startButtonText.fontSize *= 0.8f;
                         startButtonText.fontSizeMax = startButtonText.fontSize;
                         startButtonText.gameObject.transform.localPosition = Vector3.zero;
@@ -185,20 +189,16 @@ namespace TheOtherRoles.Patches {
                         }
                         startButtonPassiveButton.OnClick.AddListener((Action)(() => StopStartFunc()));
                         __instance.StartCoroutine(Effects.Lerp(.1f, new System.Action<float>((p) => {
-                            startButtonText.text = "STOP";
+                            startButtonText.text = "";
                         })));
-
                     }
-                    if (__instance.GameStartText.text.StartsWith("Starting") && CustomOptionHolder.anyPlayerCanStopStart.getBool())
-                        __instance.GameStartText.transform.localPosition = __instance.StartButton.transform.localPosition + Vector3.up * 0.6f;
                 }
-
                 // Start Timer
                 if (startingTimer > 0) {
                     startingTimer -= Time.deltaTime;
                 }
                 // Lobby timer
-                if (!GameData.Instance) return; // No instance
+                if (!GameData.Instance || !__instance.PlayerCounter) return; // No instance
 
                 if (update) currentText = __instance.PlayerCounter.text;
 
@@ -207,14 +207,14 @@ namespace TheOtherRoles.Patches {
                 int seconds = (int)timer % 60;
                 string suffix = $" ({minutes:00}:{seconds:00})";
 
-                __instance.PlayerCounter.text = currentText + suffix;
-                __instance.PlayerCounter.autoSizeTextContainer = true;
+                if (!AmongUsClient.Instance) return;
 
-                if (AmongUsClient.Instance.AmHost) {
+                if (AmongUsClient.Instance.AmHost && sendGamemode && CachedPlayer.LocalPlayer != null) {
                     MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.ShareGamemode, Hazel.SendOption.Reliable, -1);
                     writer.Write((byte) TORMapOptions.gameMode);
                     AmongUsClient.Instance.FinishRpcImmediately(writer);
                     RPCProcedure.shareGamemode((byte) TORMapOptions.gameMode);
+                    sendGamemode = false;
                 }
             }
         }
@@ -262,13 +262,15 @@ namespace TheOtherRoles.Patches {
                         // 4 = Airship
                         // 5 = Submerged
                         byte chosenMapId = 0;
-                        List<float> probabilities = new List<float>();
-                        probabilities.Add(CustomOptionHolder.dynamicMapEnableSkeld.getSelection() / 10f);
-                        probabilities.Add(CustomOptionHolder.dynamicMapEnableMira.getSelection() / 10f);
-                        probabilities.Add(CustomOptionHolder.dynamicMapEnablePolus.getSelection() / 10f);
-                        probabilities.Add(CustomOptionHolder.dynamicMapEnableAirShip.getSelection() / 10f);
-                        probabilities.Add(CustomOptionHolder.dynamicMapEnableFungle.getSelection() / 10f);
-                        probabilities.Add(CustomOptionHolder.dynamicMapEnableSubmerged.getSelection() / 10f);
+                        List<float> probabilities =
+                        [
+                            CustomOptionHolder.dynamicMapEnableSkeld.getSelection() / 10f,
+                            CustomOptionHolder.dynamicMapEnableMira.getSelection() / 10f,
+                            CustomOptionHolder.dynamicMapEnablePolus.getSelection() / 10f,
+                            CustomOptionHolder.dynamicMapEnableAirShip.getSelection() / 10f,
+                            CustomOptionHolder.dynamicMapEnableFungle.getSelection() / 10f,
+                            CustomOptionHolder.dynamicMapEnableSubmerged.getSelection() / 10f,
+                        ];
 
                         // if any map is at 100%, remove all maps that are not!
                         if (probabilities.Contains(1.0f)) {
diff --git a/TheOtherRoles/Patches/GetStringPatch.cs b/TheOtherRoles/Patches/GetStringPatch.cs
new file mode 100644 (file)
index 0000000..a39580a
--- /dev/null
@@ -0,0 +1,31 @@
+using HarmonyLib;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TheOtherRoles.Patches {
+    [HarmonyPatch]
+    class GetStringPatch {
+        [HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), new[] {
+                typeof(StringNames),
+                typeof(Il2CppReferenceArray<Il2CppSystem.Object>)
+            })]
+        public static bool Prefix(TranslationController __instance, StringNames id, ref string __result) {
+            if ((int)id < 6000) {
+                return true;
+            }
+            string ourString = "";
+
+            // For now only do this in custom options.
+            int idInt = (int)id - 6000;
+            CustomOption opt = CustomOption.options.FirstOrDefault(x => x.id == idInt);
+            ourString = opt?.name;
+
+            __result = ourString;
+
+            return false;
+        }
+    }
+}
index 101b97a88a1b8f6137e1aae84f98f3de0bbb2bf7..e2bb76795af0ac6a4a1056f312adae66db8d3ed4 100644 (file)
@@ -27,7 +27,7 @@ namespace TheOtherRoles.Patches {
                 bottomLeft = new Vector3(xpos / 2, ypos/2, -61f);
 
                 foreach (PlayerControl p in CachedPlayer.AllPlayers) {
-                    GameData.PlayerInfo data = p.Data;
+                    NetworkedPlayerInfo data = p.Data;
                     PoolablePlayer player = UnityEngine.Object.Instantiate<PoolablePlayer>(__instance.PlayerPrefab, FastDestroyableSingleton<HudManager>.Instance.transform);
                     playerPrefab = __instance.PlayerPrefab;
                     p.SetPlayerMaterialColors(player.cosmetics.currentBodySprite.BodySprite);
@@ -241,7 +241,6 @@ namespace TheOtherRoles.Patches {
                 }
             }
             public static bool Prefix(IntroCutscene __instance) {
-                if (!CustomOptionHolder.activateRoles.getBool()) return true;
                 seed = rnd.Next(5000);
                 FastDestroyableSingleton<HudManager>.Instance.StartCoroutine(Effects.Lerp(1f, new Action<float>((p) => {
                     SetRoleTexts(__instance);
index 0a9023d17e262abaf4356f081ca143e20fc39a36..e73bbf3de3c41f3bd11dad0c78df55290b4434f7 100644 (file)
@@ -17,7 +17,7 @@ namespace TheOtherRoles.Patches {
     class MeetingHudPatch {
         static bool[] selections;
         static SpriteRenderer[] renderers;
-        private static GameData.PlayerInfo target = null;
+        private static NetworkedPlayerInfo target = null;
         private const float scale = 0.65f;
         private static TMPro.TextMeshPro meetingExtraButtonText;
         private static PassiveButton[] swapperButtonList;
@@ -79,10 +79,10 @@ namespace TheOtherRoles.Patches {
                                Dictionary<byte, int> self = CalculateVotes(__instance);
                     bool tie;
                                KeyValuePair<byte, int> max = self.MaxPair(out tie);
-                    GameData.PlayerInfo exiled = GameData.Instance.AllPlayers.ToArray().FirstOrDefault(v => !tie && v.PlayerId == max.Key && !v.IsDead);
+                    NetworkedPlayerInfo exiled = GameData.Instance.AllPlayers.ToArray().FirstOrDefault(v => !tie && v.PlayerId == max.Key && !v.IsDead);
 
                     // TieBreaker 
-                    List<GameData.PlayerInfo> potentialExiled = new List<GameData.PlayerInfo>();
+                    List<NetworkedPlayerInfo> potentialExiled = new List<NetworkedPlayerInfo>();
                     bool skipIsTie = false;
                     if (self.Count > 0) {
                         Tiebreaker.isTiebreak = false;
@@ -138,7 +138,7 @@ namespace TheOtherRoles.Patches {
 
         [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.BloopAVoteIcon))]
         class MeetingHudBloopAVoteIconPatch {
-            public static bool Prefix(MeetingHud __instance, GameData.PlayerInfo voterPlayer, int index, Transform parent) {
+            public static bool Prefix(MeetingHud __instance, NetworkedPlayerInfo voterPlayer, int index, Transform parent) {
                 var spriteRenderer = UnityEngine.Object.Instantiate<SpriteRenderer>(__instance.PlayerVotePrefab);
                 var showVoteColors = !GameManager.Instance.LogicOptions.GetAnonymousVotes() ||
                                       (CachedPlayer.LocalPlayer.Data.IsDead && TORMapOptions.ghostsSeeVotes) || 
@@ -200,7 +200,7 @@ namespace TheOtherRoles.Patches {
                     bool mayorFirstVoteDisplayed = false;
                     for (int j = 0; j < states.Length; j++) {
                         MeetingHud.VoterState voterState = states[j];
-                        GameData.PlayerInfo playerById = GameData.Instance.GetPlayerById(voterState.VoterId);
+                        NetworkedPlayerInfo playerById = GameData.Instance.GetPlayerById(voterState.VoterId);
                         if (playerById == null) {
                             Debug.LogError(string.Format("Couldn't find player info for voter: {0}", voterState.VoterId));
                         } else if (i == 0 && voterState.SkippedVote && !playerById.IsDead) {
@@ -225,7 +225,7 @@ namespace TheOtherRoles.Patches {
 
         [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.VotingComplete))]
         class MeetingHudVotingCompletedPatch {
-            static void Postfix(MeetingHud __instance, [HarmonyArgument(0)]byte[] states, [HarmonyArgument(1)]GameData.PlayerInfo exiled, [HarmonyArgument(2)]bool tie)
+            static void Postfix(MeetingHud __instance, [HarmonyArgument(0)]byte[] states, [HarmonyArgument(1)]NetworkedPlayerInfo exiled, [HarmonyArgument(2)]bool tie)
             {
                 // Reset swapper values
                 Swapper.playerId1 = Byte.MaxValue;
@@ -422,7 +422,7 @@ namespace TheOtherRoles.Patches {
                 if (roleData.neutralSettings.ContainsKey((byte)roleInfo.roleId) && roleData.neutralSettings[(byte)roleInfo.roleId] == 0) continue;
                 else if (roleData.impSettings.ContainsKey((byte)roleInfo.roleId) && roleData.impSettings[(byte)roleInfo.roleId] == 0) continue;
                 else if (roleData.crewSettings.ContainsKey((byte)roleInfo.roleId) && roleData.crewSettings[(byte)roleInfo.roleId] == 0) continue;
-                else if (new List<RoleId>() { RoleId.Janitor, RoleId.Godfather, RoleId.Mafioso }.Contains(roleInfo.roleId) && CustomOptionHolder.mafiaSpawnRate.getSelection() == 0) continue;
+                else if (new List<RoleId>() { RoleId.Janitor, RoleId.Godfather, RoleId.Mafioso }.Contains(roleInfo.roleId) && (CustomOptionHolder.mafiaSpawnRate.getSelection() == 0 || GameOptionsManager.Instance.currentGameOptions.NumImpostors < 3)) continue;
                 else if (roleInfo.roleId == RoleId.Sidekick && (!CustomOptionHolder.jackalCanCreateSidekick.getBool() || CustomOptionHolder.jackalSpawnRate.getSelection() == 0)) continue;
                 if (roleInfo.roleId == RoleId.Deputy && (CustomOptionHolder.deputySpawnRate.getSelection() == 0 || CustomOptionHolder.sheriffSpawnRate.getSelection() == 0)) continue;
                 if (roleInfo.roleId == RoleId.Pursuer && CustomOptionHolder.lawyerSpawnRate.getSelection() == 0) continue;
@@ -654,7 +654,7 @@ namespace TheOtherRoles.Patches {
 
         [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.StartMeeting))]
         class StartMeetingPatch {
-            public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)]GameData.PlayerInfo meetingTarget) {
+            public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)]NetworkedPlayerInfo meetingTarget) {
                 RoomTracker roomTracker = FastDestroyableSingleton<HudManager>.Instance?.roomTracker;
                 byte roomId = Byte.MinValue;
                 if (roomTracker != null && roomTracker.LastRoom != null) {
index 213d1e2f84766167ac24ad5a3ee5d78935405966..ace0e5f25ee6f6b2267d99be04a27419c8d4f7fd 100644 (file)
@@ -1133,7 +1133,7 @@ namespace TheOtherRoles.Patches {
     [HarmonyPatch(typeof(PlayerControl), nameof(CachedPlayer.LocalPlayer.PlayerControl.CmdReportDeadBody))]
     class BodyReportPatch
     {
-        static void Postfix(PlayerControl __instance, [HarmonyArgument(0)]GameData.PlayerInfo target)
+        static void Postfix(PlayerControl __instance, [HarmonyArgument(0)]NetworkedPlayerInfo target)
         {
             // Medic or Detective report
             bool isMedicReport = Medic.medic != null && Medic.medic == CachedPlayer.LocalPlayer.PlayerControl && __instance.PlayerId == Medic.medic.PlayerId;
index 2f69c758ba60e3b5ca01f65afc538f9adcd14e4e..b9363c767724c9468cdc2f5adea3ba662ba74d00 100644 (file)
@@ -36,6 +36,7 @@ namespace TheOtherRoles.Patches {
     {
         private static TextBoxTMP ipField;
         private static TextBoxTMP portField;
+        private static GameObject serverWarning;
 
         public static void Postfix(RegionMenu __instance) {
             if (!__instance.TryCast<RegionMenu>()) return;
@@ -141,6 +142,20 @@ namespace TheOtherRoles.Patches {
                     TheOtherRolesPlugin.UpdateRegions();
                 }
             }
+
+            if (serverWarning == null) {
+                var tmplt = __instance.ButtonPool.activeChildren[^1] ;
+                serverWarning = GameObject.Instantiate(tmplt.transform.GetChild(0).gameObject, tmplt.transform);
+                var comp = serverWarning.GetComponent<TMPro.TextMeshPro>();
+                comp.fontSizeMin = 2;
+                comp.fontSizeMax = 2;
+                serverWarning.transform.localPosition = new Vector3(0f, -3f, -10f);
+                __instance.StartCoroutine(Effects.Lerp(0.1f, new Action<float>((p) => {
+                    comp.text = Helpers.cs(Color.red, "Vanilla Servers Are Currently Not Compatible With TOR");
+                })));
+                serverWarning.SetActive(true);
+            }
+
         }
     }
 
index 31c7855d76cc452ac532185a92cd7bcff756abf8..ded2828b3bdbadc7772fd97c6cc7321105359cf5 100644 (file)
@@ -11,10 +11,10 @@ using static TheOtherRoles.TheOtherRoles;
 using TheOtherRoles.CustomGameModes;
 
 namespace TheOtherRoles.Patches {
-    [HarmonyPatch(typeof(RoleOptionsCollectionV07), nameof(RoleOptionsCollectionV07.GetNumPerGame))]
+    [HarmonyPatch(typeof(RoleOptionsCollectionV08), nameof(RoleOptionsCollectionV08.GetNumPerGame))]
     class RoleOptionsDataGetNumPerGamePatch{
         public static void Postfix(ref int __result) {
-            if (CustomOptionHolder.activateRoles.getBool() && GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.Normal) __result = 0; // Deactivate Vanilla Roles if the mod roles are active
+            if (GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.Normal) __result = 0; // Deactivate Vanilla Roles if the mod roles are active
         }
     }
 
@@ -52,8 +52,7 @@ namespace TheOtherRoles.Patches {
             AmongUsClient.Instance.FinishRpcImmediately(writer);
             RPCProcedure.resetVariables();
             if (TORMapOptions.gameMode == CustomGamemodes.HideNSeek || TORMapOptions.gameMode == CustomGamemodes.PropHunt || GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return; // Don't assign Roles in Hide N Seek
-            if (CustomOptionHolder.activateRoles.getBool()) // Don't assign Roles in Tutorial or if deactivated
-                assignRoles();
+            assignRoles();
         }
 
         private static void assignRoles() {
@@ -66,7 +65,7 @@ namespace TheOtherRoles.Patches {
             assignRoleTargets(data); // Assign targets for Lawyer & Prosecutor
             if (isGuesserGamemode) assignGuesserGamemode();
             assignModifiers(); // Assign modifier
-            setRolesAgain();
+            //setRolesAgain();
         }
 
         public static RoleAssignmentData getRoleAssignmentData() {
@@ -524,7 +523,7 @@ namespace TheOtherRoles.Patches {
 
             playerRoleMap.Add(new Tuple<byte, byte>(playerId, roleId));
 
-            MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(CachedPlayer.LocalPlayer.PlayerControl.NetId, (byte)CustomRPC.SetRole, Hazel.SendOption.Reliable, -1);
+            MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetRole, Hazel.SendOption.Reliable, -1);
             writer.Write(roleId);
             writer.Write(playerId);
             AmongUsClient.Instance.FinishRpcImmediately(writer);
index 18d48a222093d109e62c3ae13add6dc5f4519784..26c73923136234f85f13ab68e2eb9e3f0e681ee2 100644 (file)
@@ -14,7 +14,7 @@ namespace TheOtherRoles.Patches {
     {
         [HarmonyPrefix]
         [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.CalculateLightRadius))]
-        public static bool Prefix(ref float __result, ShipStatus __instance, [HarmonyArgument(0)] GameData.PlayerInfo player) {
+        public static bool Prefix(ref float __result, ShipStatus __instance, [HarmonyArgument(0)] NetworkedPlayerInfo player) {
             if ((!__instance.Systems.ContainsKey(SystemTypes.Electrical) && !Helpers.isFungle()) || GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return true;
 
             // If Game Mode is PropHunt:
index 6c6569f1e702b6afbd81d05cb79bc5f44d4f3c3e..0da7c82fb8ca8d404b5fe4beb5698caf06948fc8 100644 (file)
@@ -19,7 +19,7 @@ namespace TheOtherRoles.Patches {
     [HarmonyPatch(typeof(Vent), nameof(Vent.CanUse))]
     public static class VentCanUsePatch
     {
-        public static bool Prefix(Vent __instance, ref float __result, [HarmonyArgument(0)] GameData.PlayerInfo pc, [HarmonyArgument(1)] ref bool canUse, [HarmonyArgument(2)] ref bool couldUse) {
+        public static bool Prefix(Vent __instance, ref float __result, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] ref bool canUse, [HarmonyArgument(2)] ref bool couldUse) {
             if (GameOptionsManager.Instance.currentGameOptions.GameMode == GameModes.HideNSeek) return true;
             float num = float.MaxValue;
             PlayerControl @object = pc.Object;
@@ -271,7 +271,7 @@ namespace TheOtherRoles.Patches {
 
     [HarmonyPatch(typeof(Console), nameof(Console.CanUse))]
     public static class ConsoleCanUsePatch {
-        public static bool Prefix(ref float __result, Console __instance, [HarmonyArgument(0)] GameData.PlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse) {
+        public static bool Prefix(ref float __result, Console __instance, [HarmonyArgument(0)] NetworkedPlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse) {
             canUse = couldUse = false;
             if (Swapper.swapper != null && Swapper.swapper == CachedPlayer.LocalPlayer.PlayerControl)
                 return !__instance.TaskTypes.Any(x => x == TaskTypes.FixLights || x == TaskTypes.FixComms);
@@ -340,7 +340,7 @@ namespace TheOtherRoles.Patches {
                 if (Hacker.hacker != null && Hacker.hacker == CachedPlayer.LocalPlayer.PlayerControl && Hacker.hackerTimer > 0) {
                     for (int k = 0; k < __instance.vitals.Length; k++) {
                         VitalsPanel vitalsPanel = __instance.vitals[k];
-                        GameData.PlayerInfo player = vitalsPanel.PlayerInfo;
+                        NetworkedPlayerInfo player = vitalsPanel.PlayerInfo;
 
                         // Hacker update
                         if (vitalsPanel.IsDead) {
@@ -416,7 +416,7 @@ namespace TheOtherRoles.Patches {
                                     num2++;
                                     DeadBody bodyComponent = collider2D.GetComponent<DeadBody>();
                                     if (bodyComponent) {
-                                        GameData.PlayerInfo playerInfo = GameData.Instance.GetPlayerById(bodyComponent.ParentId);
+                                        NetworkedPlayerInfo playerInfo = GameData.Instance.GetPlayerById(bodyComponent.ParentId);
                                         if (playerInfo != null) {
                                             var color = Palette.PlayerColors[playerInfo.DefaultOutfit.ColorId];
                                             if (Hacker.onlyColorType)
index 2cbee9abfa4babbdc022270188879b1bd92d6068..39dcf97287c415f8e4b72cd60ce545fbab795f9c 100644 (file)
@@ -19,7 +19,7 @@ public class CachedPlayer
     public PlayerControl PlayerControl;
     public PlayerPhysics PlayerPhysics;
     public CustomNetworkTransform NetTransform;
-    public GameData.PlayerInfo Data;
+    public NetworkedPlayerInfo Data;
     public byte PlayerId;
     
     public static implicit operator bool(CachedPlayer player)
@@ -99,7 +99,7 @@ public static class CachedPlayerPatches
         CachedPlayer.PlayerPtrs.Remove(__instance.Pointer);
     }
     
-    [HarmonyPatch(typeof(GameData), nameof(GameData.Deserialize))]
+    [HarmonyPatch(typeof(NetworkedPlayerInfo), nameof(NetworkedPlayerInfo.Deserialize))]
     [HarmonyPostfix]
     public static void AddCachedDataOnDeserialize()
     {
index 8c1166366a6b4ac7390d512d0ad4d48543ec6e34..1c9da7bf2d0fbed9f975a6ac97b41e60434f42ce 100644 (file)
@@ -16,6 +16,7 @@ using TheOtherRoles.CustomGameModes;
 using AmongUs.Data;
 using AmongUs.GameOptions;
 using Assets.CoreScripts;
+using Reactor.Utilities.Extensions;
 namespace TheOtherRoles
 {
     public enum RoleId {
@@ -83,7 +84,7 @@ namespace TheOtherRoles
     {
         // Main Controls
 
-        ResetVaribles = 60,
+        ResetVaribles = 100,
         ShareOptions,
         ForceEnd,
         WorkaroundSetRoles,
@@ -101,7 +102,7 @@ namespace TheOtherRoles
 
         // Role functionality
 
-        EngineerFixLights = 101,
+        EngineerFixLights = 120,
         EngineerFixSubmergedOxygen,
         EngineerUsedRepair,
         CleanBody,
@@ -197,7 +198,7 @@ namespace TheOtherRoles
                     uint optionId = reader.ReadPackedUInt32();
                     uint selection = reader.ReadPackedUInt32();
                     CustomOption option = CustomOption.options.First(option => option.id == (int)optionId);
-                    option.updateSelection((int)selection);
+                    option.updateSelection((int)selection, i == numberOfOptions - 1);
                 }
             } catch (Exception e) {
                 TheOtherRolesPlugin.Logger.LogError("Error while deserializing options: " + e.Message);
@@ -212,7 +213,7 @@ namespace TheOtherRoles
                 {
                     
                     GameData.Instance.GetPlayerById(player.PlayerId); // player.RemoveInfected(); (was removed in 2022.12.08, no idea if we ever need that part again, replaced by these 2 lines.) 
-                    player.SetRole(RoleTypes.Crewmate);
+                    player.CoSetRole(RoleTypes.Crewmate, true);
 
                     player.MurderPlayer(player);
                     player.Data.IsDead = true;
@@ -222,6 +223,9 @@ namespace TheOtherRoles
 
         public static void shareGamemode(byte gm) {
             TORMapOptions.gameMode = (CustomGamemodes) gm;
+            LobbyViewSettingsPatch.currentButtons?.ForEach(x => x.gameObject?.Destroy());
+            LobbyViewSettingsPatch.currentButtons?.Clear();
+            LobbyViewSettingsPatch.currentButtonTypes?.Clear();
         }
 
         public static void stopStart(byte playerId) {
@@ -249,7 +253,7 @@ namespace TheOtherRoles
         public static void setRole(byte roleId, byte playerId) {
             foreach (PlayerControl player in CachedPlayer.AllPlayers) {
                 if (player.PlayerId == playerId) {
-                    switch((RoleId)roleId) {
+                    switch ((RoleId)roleId) {
                     case RoleId.Jester:
                         Jester.jester = player;
                         break;
@@ -259,7 +263,7 @@ namespace TheOtherRoles
                     case RoleId.Portalmaker:
                         Portalmaker.portalmaker = player;
                         break;
-                        case RoleId.Engineer:
+                    case RoleId.Engineer:
                         Engineer.engineer = player;
                         break;
                     case RoleId.Sheriff:
@@ -389,7 +393,7 @@ namespace TheOtherRoles
                     }
                     if (AmongUsClient.Instance.AmHost && Helpers.roleCanUseVents(player) && !player.Data.Role.IsImpostor) {
                         player.RpcSetRole(RoleTypes.Engineer);
-                        player.SetRole(RoleTypes.Engineer);
+                        player.CoSetRole(RoleTypes.Engineer, true);
                     }                   
                 }
             }
@@ -981,6 +985,7 @@ namespace TheOtherRoles
                 }
             }
 
+            bool lawyerDiedAdditionally = false;
             if (Lawyer.lawyer != null && !Lawyer.isProsecutor && Lawyer.lawyer.PlayerId == killerId && Lawyer.target != null && Lawyer.target.PlayerId == dyingTargetId) {
                 // Lawyer guessed client.
                 if (CachedPlayer.LocalPlayer.PlayerControl == Lawyer.lawyer) {
@@ -988,6 +993,8 @@ namespace TheOtherRoles
                     if (MeetingHudPatch.guesserUI != null) MeetingHudPatch.guesserUIExitButton.OnClick.Invoke();
                 }
                 Lawyer.lawyer.Exiled();
+                lawyerDiedAdditionally = true;
+                GameHistory.overrideDeathReasonAndKiller(Lawyer.lawyer, DeadPlayer.CustomDeathReason.LawyerSuicide, guesser);
             }
 
             dyingTarget.Exiled();
@@ -997,15 +1004,15 @@ namespace TheOtherRoles
             HandleGuesser.remainingShots(killerId, true);
             if (Constants.ShouldPlaySfx()) SoundManager.Instance.PlaySound(dyingTarget.KillSfx, false, 0.8f);
             if (MeetingHud.Instance) {
-                MeetingHudPatch.swapperCheckAndReturnSwap(MeetingHud.Instance, dyingTargetId);
                 foreach (PlayerVoteArea pva in MeetingHud.Instance.playerStates) {
-                    if (pva.TargetPlayerId == dyingTargetId || pva.TargetPlayerId == partnerId) {
+                    if (pva.TargetPlayerId == dyingTargetId || pva.TargetPlayerId == partnerId || lawyerDiedAdditionally && Lawyer.lawyer.PlayerId == pva.TargetPlayerId) {
                         pva.SetDead(pva.DidReport, true);
                         pva.Overlay.gameObject.SetActive(true);
+                        MeetingHudPatch.swapperCheckAndReturnSwap(MeetingHud.Instance, pva.TargetPlayerId);
                     }
 
                     //Give players back their vote if target is shot dead
-                    if (pva.VotedFor != dyingTargetId || pva.VotedFor != partnerId) continue;
+                    if (pva.VotedFor != dyingTargetId && pva.VotedFor != partnerId && (!lawyerDiedAdditionally || Lawyer.lawyer.PlayerId != pva.VotedFor)) continue;
                     pva.UnsetVote();
                     var voteAreaPlayer = Helpers.playerById(pva.TargetPlayerId);
                     if (!voteAreaPlayer.AmOwner) continue;
@@ -1311,7 +1318,6 @@ namespace TheOtherRoles
         }
 
         public static void yoyoBlink(bool isFirstJump, byte[] buff) {
-            TheOtherRolesPlugin.Logger.LogMessage($"blink fistjumpo: {isFirstJump}");
             if (Yoyo.yoyo == null || Yoyo.markedLocation == null) return;
             var markedPos = (Vector3)Yoyo.markedLocation;
             Yoyo.yoyo.NetTransform.SnapTo(markedPos);
diff --git a/TheOtherRoles/Resources/Copy.png b/TheOtherRoles/Resources/Copy.png
new file mode 100644 (file)
index 0000000..1db34bb
Binary files /dev/null and b/TheOtherRoles/Resources/Copy.png differ
diff --git a/TheOtherRoles/Resources/CopyActive.png b/TheOtherRoles/Resources/CopyActive.png
new file mode 100644 (file)
index 0000000..f19ecd7
Binary files /dev/null and b/TheOtherRoles/Resources/CopyActive.png differ
diff --git a/TheOtherRoles/Resources/CopyPasteBG.png b/TheOtherRoles/Resources/CopyPasteBG.png
new file mode 100644 (file)
index 0000000..c8f47cc
Binary files /dev/null and b/TheOtherRoles/Resources/CopyPasteBG.png differ
diff --git a/TheOtherRoles/Resources/Minus_Button.png b/TheOtherRoles/Resources/Minus_Button.png
new file mode 100644 (file)
index 0000000..8453665
Binary files /dev/null and b/TheOtherRoles/Resources/Minus_Button.png differ
diff --git a/TheOtherRoles/Resources/Minus_ButtonActive.png b/TheOtherRoles/Resources/Minus_ButtonActive.png
new file mode 100644 (file)
index 0000000..2cd4b5a
Binary files /dev/null and b/TheOtherRoles/Resources/Minus_ButtonActive.png differ
diff --git a/TheOtherRoles/Resources/Paste.png b/TheOtherRoles/Resources/Paste.png
new file mode 100644 (file)
index 0000000..8bae0fc
Binary files /dev/null and b/TheOtherRoles/Resources/Paste.png differ
diff --git a/TheOtherRoles/Resources/PasteActive.png b/TheOtherRoles/Resources/PasteActive.png
new file mode 100644 (file)
index 0000000..b80d73b
Binary files /dev/null and b/TheOtherRoles/Resources/PasteActive.png differ
diff --git a/TheOtherRoles/Resources/Plus_Button.png b/TheOtherRoles/Resources/Plus_Button.png
new file mode 100644 (file)
index 0000000..35335d5
Binary files /dev/null and b/TheOtherRoles/Resources/Plus_Button.png differ
diff --git a/TheOtherRoles/Resources/Plus_ButtonActive.png b/TheOtherRoles/Resources/Plus_ButtonActive.png
new file mode 100644 (file)
index 0000000..ac30e9b
Binary files /dev/null and b/TheOtherRoles/Resources/Plus_ButtonActive.png differ
diff --git a/TheOtherRoles/Resources/Settings_Button.png b/TheOtherRoles/Resources/Settings_Button.png
new file mode 100644 (file)
index 0000000..9119e37
Binary files /dev/null and b/TheOtherRoles/Resources/Settings_Button.png differ
diff --git a/TheOtherRoles/Resources/Settings_ButtonActive.png b/TheOtherRoles/Resources/Settings_ButtonActive.png
new file mode 100644 (file)
index 0000000..813c937
Binary files /dev/null and b/TheOtherRoles/Resources/Settings_ButtonActive.png differ
index 96ae2d3190e97adaf4ebfb9c27a71d562e88ab56..8ce050a5b501179f228f08b697137da7e77d80a2 100644 (file)
@@ -6,7 +6,7 @@ namespace TheOtherRoles {
     [HarmonyPatch]
     public static class TasksHandler {
 
-        public static Tuple<int, int> taskInfo(GameData.PlayerInfo playerInfo) {
+        public static Tuple<int, int> taskInfo(NetworkedPlayerInfo playerInfo) {
             int TotalTasks = 0;
             int CompletedTasks = 0;
             if (!playerInfo.Disconnected && playerInfo.Tasks != null &&
index 9c056c16f17ea3fb1ba59c7a5b76cb08ea3461f3..500b874776757079542d5fddf341b2727a7b8eeb 100644 (file)
@@ -1,14 +1,15 @@
 <Project Sdk="Microsoft.NET.Sdk">
     <PropertyGroup>
         <TargetFramework>net6.0</TargetFramework>
-        <Version>4.5.3</Version>
+        <Version>4.6.0</Version>
         <Description>TheOtherRoles</Description>
         <Authors>Eisbison</Authors>
                <LangVersion>latest</LangVersion>
         <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
         <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
-        <PlatformTarget>x86</PlatformTarget>
+        <PlatformTarget>AnyCPU</PlatformTarget>
         <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
+        <Platforms>AnyCPU</Platforms>
     </PropertyGroup>
 
     <ItemGroup>
@@ -16,9 +17,9 @@
     </ItemGroup>
    
        <ItemGroup>
-               <PackageReference Include="AmongUs.GameLibs.Steam" Version="2024.3.5" />
+               <PackageReference Include="AmongUs.GameLibs.Steam" Version="2024.6.18" />
                <PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" />
-               <PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.688" />
+               <PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.692" />
         <PackageReference Include="Reactor" Version="2.2.0" />
     </ItemGroup>
    
@@ -32,5 +33,5 @@
     <Target Name="CopyCustomContent" AfterTargets="AfterBuild" Condition="Exists('$(AmongUsLatest)/BepInEx/plugins/')">
         <Message Text="Second occurrence" />
         <Copy SourceFiles="$(ProjectDir)\bin\$(Configuration)\net6.0\TheOtherRoles.dll" DestinationFolder="$(AmongUsLatest)/BepInEx/plugins/" />
-    </Target>
+       </Target>
 </Project>
index 3bcb0fd0c0f3f6a025c0f4f39693c23c92a54e46..e83bd997053a6b08d0024e42fcb0ed8aa19d8443 100644 (file)
@@ -4,9 +4,9 @@
     "net6.0": {
       "AmongUs.GameLibs.Steam": {
         "type": "Direct",
-        "requested": "[2024.3.5, )",
-        "resolved": "2024.3.5",
-        "contentHash": "5KOcBSFnql0DmrL82GikWb5I+KLvD8h8RsS28BKTCws2fPKwWauUm/L9Zh73pIHcnOMCpvnAxWeZh/AqxAEI0Q=="
+        "requested": "[2024.6.18, )",
+        "resolved": "2024.6.18",
+        "contentHash": "xb+HP1xXn4/ES8AgXpk9xeoW568LFYw5NTjY6bHwd6vQjHDf2kT1xHMmQ1me5Vfee/Gp69YIMZDXUAUToG7Elg=="
       },
       "BepInEx.IL2CPP.MSBuild": {
         "type": "Direct",
       },
       "BepInEx.Unity.IL2CPP": {
         "type": "Direct",
-        "requested": "[6.0.0-be.688, )",
-        "resolved": "6.0.0-be.688",
-        "contentHash": "a68J6PA9AdgYlj8HeuEK1hM4Vv+j1x/6TflK5/PaYAd05/TPdjNI09LsSTIOaS9hdWZwCcpPEw/HxLhXaQKodw==",
+        "requested": "[6.0.0-be.692, )",
+        "resolved": "6.0.0-be.692",
+        "contentHash": "rYjnJCN2APD/04dZUKhRCbu30jhzseIKd0+pfaWWgfDJNggd8rq+whEzM/ZC0fEkkLgcIkEgbtX2LuSqsCrIgg==",
         "dependencies": {
-          "BepInEx.Core": "6.0.0-be.688",
-          "BepInEx.Unity.Common": "6.0.0-be.688",
+          "BepInEx.Core": "6.0.0-be.692",
+          "BepInEx.Unity.Common": "6.0.0-be.692",
           "HarmonyX": "2.10.1",
-          "Iced": "1.18.0",
-          "Il2CppInterop.Generator": "1.4.6-ci.389",
-          "Il2CppInterop.HarmonySupport": "1.4.6-ci.389",
-          "Il2CppInterop.Runtime": "1.4.6-ci.389",
+          "Iced": "1.20.0",
+          "Il2CppInterop.Generator": "1.4.6-ci.426",
+          "Il2CppInterop.HarmonySupport": "1.4.6-ci.426",
+          "Il2CppInterop.Runtime": "1.4.6-ci.426",
           "MonoMod.RuntimeDetour": "22.5.1.1",
-          "Samboy063.Cpp2IL.Core": "2022.1.0-development.866"
+          "Samboy063.Cpp2IL.Core": "2022.1.0-development.972"
         }
       },
       "Reactor": {
       },
       "AsmResolver": {
         "type": "Transitive",
-        "resolved": "5.1.0",
-        "contentHash": "7PjujQzgQ3wjzqZYT4CY8SV6zx7FY6swIwj3Yk4QLolLqo9sBPb7FLF3W30QFvCsCkNfiVWXlSbeZKs4xGgQOQ=="
+        "resolved": "5.5.0",
+        "contentHash": "IuOC+b/D/da4fohYVNwo/NL+8w+q89O9B32bLotegJ+hmFlBEpQEKgtyhxc9ZfEd+x0KzwzD52RISuyLgf/BAA=="
       },
       "AsmResolver.DotNet": {
         "type": "Transitive",
-        "resolved": "5.1.0",
-        "contentHash": "oKrBU94OaSrbbTwydvpLRFalYxozrNXGkl13nIkm823ZFQtPNYOiOMJb5DQLvkCJlWyis7q865tg803T5zg9IA==",
+        "resolved": "5.5.0",
+        "contentHash": "T19DazP0h4qKXwPspTEB0ZzwlftPuvVAd68HhsS8eNYd9lRd/rtppcBmM2QLQdZeGGNJc+QEzLiAW+wrA3nKAw==",
         "dependencies": {
-          "AsmResolver.PE": "5.1.0",
-          "System.Text.Json": "6.0.7"
+          "AsmResolver.PE": "5.5.0",
+          "System.Text.Json": "6.0.8"
         }
       },
       "AsmResolver.PE": {
         "type": "Transitive",
-        "resolved": "5.1.0",
-        "contentHash": "XD3iAgLSInJIODKUUlpHWXf8MR9H1SFMb1lsmabb4GxxxnDQRPjMxjglv2NOCjQQuNB2Oh0bvjHE7ewf82UqyQ==",
+        "resolved": "5.5.0",
+        "contentHash": "bSPe0A+z4iEAabpD9h7ACQ5dkcTirx4fx05P194u/+OIUqlexHf7Zq/PEPdOkesbqHoZmgVmJ1H0GWqqouvZfA==",
         "dependencies": {
-          "AsmResolver.PE.File": "5.1.0"
+          "AsmResolver.PE.File": "5.5.0"
         }
       },
       "AsmResolver.PE.File": {
         "type": "Transitive",
-        "resolved": "5.1.0",
-        "contentHash": "YituBYe0Fh471sXQMfu+f4tWKX/JZvRwrX6g/SVsr4XkUIUzYi/aGT3/QvjHoYx19fE1KYOB6zBKqPkkOK7HPw==",
+        "resolved": "5.5.0",
+        "contentHash": "XHWHnPQf0e0VEJPTaWMoiajuikF0n0fDXS2XWzEXM+/xcY+LABsp1p7ETlg+bFsDVITQRtNTa/xV8eSDlSZjNQ==",
         "dependencies": {
-          "AsmResolver": "5.1.0"
+          "AsmResolver": "5.5.0"
         }
       },
-      "AssetRipper.Primitives": {
+      "AssetRipper.CIL": {
         "type": "Transitive",
-        "resolved": "2.1.0",
-        "contentHash": "nrgwUMa69ztOfMKbmytNI3mU/fuN3eWptq2Mu8aLg2ly394w51KJbUx5z477HbRvabD8TD8rM4wRe6EBqB2xdA=="
+        "resolved": "1.0.0",
+        "contentHash": "l639dKLllpJ5TcX+Z1OVYz+hsKVZyMpEm59Dl4Qd6YrCHPVj9yPtF/UNjn9nFxoDm7suEFP/0vlZD/bSeXjz6Q==",
+        "dependencies": {
+          "AsmResolver.DotNet": "5.5.0"
+        }
       },
-      "AssetRipper.VersionUtilities": {
+      "AssetRipper.Gee.External.Capstone": {
         "type": "Transitive",
-        "resolved": "1.2.1",
-        "contentHash": "knQ/W1YwTZS2AbdaZh+nhyyBEZQPQDcahhSOnh88i+cdg4/FEoFJiCwaavgFvCMNuUeHTbcZc4qttF8WQ8xLIA=="
+        "resolved": "2.3.1",
+        "contentHash": "WVujToXc2sB5nVEY4iMpjhsQaqGw5RjG3c0Hl1qT/pZMbfwtafpaOwAa0G/GS5gd2jcuJwrsG880Pkyjkhi3vQ=="
+      },
+      "AssetRipper.Primitives": {
+        "type": "Transitive",
+        "resolved": "3.1.1",
+        "contentHash": "GhFAVMWpG8MyZscQxwYCd1HSS36UhIQeW0Gn9iPYiininZWlo8RTV9tGYv0CNNXw5bODYJtXf4qiqo6sQOVAEg=="
       },
       "BepInEx.Core": {
         "type": "Transitive",
-        "resolved": "6.0.0-be.688",
-        "contentHash": "34VErIttx6PckRukoaRXIb6ZF5oby+9Oktt9E3ZafOGzA0lBWOmY/BKHfg766XZBplE06KijHp+vrryCjfLP7Q==",
+        "resolved": "6.0.0-be.692",
+        "contentHash": "I/JuhVhOXUFRrSxy7MqMHpygKoYNt39XY5V8e7PTLbq+nfCBGYzOhszcPx90Wj5xGPx6IFuABJocWAbFDHUddA==",
         "dependencies": {
           "HarmonyX": "2.10.1",
           "MonoMod.Utils": "22.5.1.1",
       },
       "BepInEx.Unity.Common": {
         "type": "Transitive",
-        "resolved": "6.0.0-be.688",
-        "contentHash": "RRPG9sEgIdGgut0LOSQopW+6mMpE0LDggKZWfLBBeaJj1p0WFrVBCqEAruFLO0FrwT/+dEC7EtV62n13RV1JfA==",
+        "resolved": "6.0.0-be.692",
+        "contentHash": "QYsp8Sf4kQwmx4qwFLhS7SW+Dp67iBibb0zo5IdMQXGmS0KY2WH7/SZ+fFmG6ce06BT+E58wsxk0rU6NW0qWbg==",
         "dependencies": {
-          "AssetRipper.VersionUtilities": "1.2.1",
+          "AssetRipper.Primitives": "3.1.1",
           "MonoMod.Utils": "22.5.1.1"
         }
       },
       },
       "Iced": {
         "type": "Transitive",
-        "resolved": "1.18.0",
-        "contentHash": "G60lZOvbvqttA+SBSv/yY6/wUboXKJlkffhSNR9iOrx0M5gpcK1TRr6xrFR+qAhqIAhvrsPF1jkn9fYb4lEufQ=="
+        "resolved": "1.20.0",
+        "contentHash": "cjk+vNDIatLI5vQ22tOCAzsgowZ32Ob1Fy4ljQSfqfzMe5ATKXU+dMPRE6+cIUUFetoyyWkUJArJoxe3QwDXAA=="
       },
       "Il2CppInterop.Common": {
         "type": "Transitive",
-        "resolved": "1.4.6-ci.389",
-        "contentHash": "KTyf2f66Q2mS9a6xhvoPWwD0VzRIoskPMVQehaVMo1dx4Di1FPFsKqukQ+ob6wgP5Rbnx53kiH0PY+IRSb35XA==",
+        "resolved": "1.4.6-ci.426",
+        "contentHash": "pI0kU0qqJKMP6z9eFz4+WJtGIwklfPxW2yWEY9vKnrN9bbYMusK3v5uFWV8al7S/HPSATV5jNWH1hyTvP7kglA==",
         "dependencies": {
           "Iced": "1.17.0",
           "Microsoft.Extensions.Logging.Abstractions": "6.0.1",
       },
       "Il2CppInterop.Generator": {
         "type": "Transitive",
-        "resolved": "1.4.6-ci.389",
-        "contentHash": "XJX4sn/RzAEBNIZZXuyDcLZrFx5tCoahujDu5aKWjApiMj/nTRQAxZn17daIIvd9aHqLaAfiWWth5QDLIt2bKw==",
+        "resolved": "1.4.6-ci.426",
+        "contentHash": "kecdx/vbNl0RtfzfYW592jU8PMyq1JbzpvoJSvqwO+tV6icp9SljXy6yG8bT/wt0gaPj9mFUNDTe2Wu6M6XGZQ==",
         "dependencies": {
-          "Il2CppInterop.Common": "1.4.6-ci.389",
+          "Il2CppInterop.Common": "1.4.6-ci.426",
           "Mono.Cecil": "0.11.3"
         }
       },
       "Il2CppInterop.HarmonySupport": {
         "type": "Transitive",
-        "resolved": "1.4.6-ci.389",
-        "contentHash": "Xd2zK6sLqwA0ReyUy83SWKcALwY99fq6vVL5gFOMN5Ct8OOVhtNIws0ysCWsfx1GL0RJiRYfR4pza/MmWRz4PQ==",
+        "resolved": "1.4.6-ci.426",
+        "contentHash": "rd2T5o6SybIc12hmX3HktTF5n27hFb0w4mNSExq7h1YsmrNlt7x+Ac1MBnnB0JwPLIg7w8LjnKjoIX6Gf626ng==",
         "dependencies": {
           "HarmonyX": "2.10.0",
-          "Il2CppInterop.Runtime": "1.4.6-ci.389"
+          "Il2CppInterop.Runtime": "1.4.6-ci.426"
         }
       },
       "Il2CppInterop.Runtime": {
         "type": "Transitive",
-        "resolved": "1.4.6-ci.389",
-        "contentHash": "nzYjuVzDG/O8+AQ8ax3WVHf+ZVsQKrVtp/yvuW8XoEPLdkbgryIrMo75dvN+tPqxOU3o2MPt9MZ9j25P5aVJMw==",
+        "resolved": "1.4.6-ci.426",
+        "contentHash": "0O0oI7gOqJixrsjvh1firhuGYK3Yr0uDLp6Q+t5CfcTMmeEX8Plk3pqAP9ZYyilBvh7uW0gv4Golqz08L1GXug==",
         "dependencies": {
           "Iced": "1.17.0",
-          "Il2CppInterop.Common": "1.4.6-ci.389"
+          "Il2CppInterop.Common": "1.4.6-ci.426"
         }
       },
-      "js6pak.Gee.External.Capstone": {
-        "type": "Transitive",
-        "resolved": "2.1.0",
-        "contentHash": "YYpq7NM50bSSVUDjXyV/eiITk6syXqItPjKBOb3jEWS6RFsk0DNhpWMPW6b3hKDmArARuWDU6S2pVu1IeVrvIA=="
-      },
       "Microsoft.Extensions.Logging.Abstractions": {
         "type": "Transitive",
         "resolved": "6.0.1",
       },
       "Samboy063.Cpp2IL.Core": {
         "type": "Transitive",
-        "resolved": "2022.1.0-development.866",
-        "contentHash": "QPMuix/3jRngWBdNSLhAbm9BHYf95Ln1Ph1eCK/cDZdVibxFDFP3a6Yczyx1p7GbN7bRQwrhs2skPJSS/z3m2w==",
+        "resolved": "2022.1.0-pre-release.13",
+        "contentHash": "d3/E3e2rCDlnRiFdNyLxE94XKabsCdMEzVblzsraodYxQhjCXacn75KHkp3Jwj+6Y8A3usehMInDWep4L/+TQQ==",
         "dependencies": {
-          "AsmResolver.DotNet": "5.1.0",
+          "AsmResolver.DotNet": "5.5.0",
+          "AssetRipper.CIL": "1.0.0",
+          "AssetRipper.Gee.External.Capstone": "2.3.1",
           "Disarm": "2022.1.0-master.26",
-          "Iced": "1.18.0",
-          "Samboy063.LibCpp2IL": "2022.1.0-development.866",
-          "StableNameDotNet": "0.1.0-development.866",
-          "js6pak.Gee.External.Capstone": "2.1.0"
+          "Iced": "1.20.0",
+          "Samboy063.LibCpp2IL": "2022.1.0-pre-release.13",
+          "StableNameDotNet": "0.1.0-pre-release.13"
         }
       },
       "Samboy063.LibCpp2IL": {
       },
       "System.Text.Json": {
         "type": "Transitive",
-        "resolved": "6.0.7",
-        "contentHash": "/Tf/9XjprpHolbcDOrxsKVYy/mUG/FS7aGd9YUgBVEiHeQH4kAE0T1sMbde7q6B5xcrNUsJ5iW7D1RvHudQNqA==",
+        "resolved": "6.0.8",
+        "contentHash": "WhW6zPEgRZoo+c1NEvSSmrME4+LqXmW6tcsRFsEiSMeco+qZ9rpLs7tT53EIkE/s9GNTYS4/STQoaGiKDSWifQ==",
         "dependencies": {
           "System.Runtime.CompilerServices.Unsafe": "6.0.0",
           "System.Text.Encodings.Web": "6.0.0"