# 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)
<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)
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
{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
// 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);
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);
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);
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);
// 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));
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();
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);
},
() => { 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
--- /dev/null
+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);
+ }));
+
+ }
+ }
+ }
+}
using TheOtherRoles.Utilities;
using TMPro;
using UnityEngine;
+using static TheOtherRoles.Snitch;
+using static UnityEngine.GraphicsBuffer;
namespace TheOtherRoles.CustomGameModes {
[HarmonyPatch]
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()}");
}
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);
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);
}
public static void dangerMeterUpdate() {
+ if (!HudManager.Instance || !HudManager.Instance.DangerMeter) return;
if (HudManager.Instance.DangerMeter.gameObject.active) {
float dist = 55f;
float dist2 = 15f;
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) {
[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) {
[HarmonyPrefix]
public static bool CheckClickPatch(KillButton __instance) {
if (!PropHunt.isPropHuntGM) return true;
- __instance.DoClick();
+ __instance.DoClick();
return false;
}
[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) {
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) {
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))]
// 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);
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);
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);
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);
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);
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);
// 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);
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);
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
}
// 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();
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.
}
}
}
- 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)
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);
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; }
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");
// 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;
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)) {
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
enableSoundEffects = TheOtherRolesPlugin.EnableSoundEffects.Value;
enableHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
ShowVentsOnMap = TheOtherRolesPlugin.ShowVentsOnMap.Value;
-
+ ShowChatNotifications = TheOtherRolesPlugin.ShowChatNotifications.Value;
+
//Patches.ShouldAlwaysHorseAround.isHorseMode = TheOtherRolesPlugin.EnableHorseMode.Value;
}
}
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()
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;
}
}
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
[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;
{
spriteAnimNodeSync.NodeId = __instance.Hat.NoBounce ? 1 : 0;
}
-
if (__instance.Hat.InFront)
{
__instance.BackLayer.enabled = false;
__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;
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++)
{
}
__instance.scroller.ContentYBounds.max = -(yOffset + 4.1f);
+ return false;
}
private static float CreateHatPackage(List<Tuple<HatData, HatExtension>> hats, string packageName, float yStart,
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");
using BepInEx.Unity.IL2CPP;
using BepInEx;
using static ShipStatus;
+using TMPro;
namespace TheOtherRoles {
public class CustomOption {
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;
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);
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
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) {
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 { }
}
}
- 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();
}
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)
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();
{
public static void Postfix()
{
- CustomOption.ShareOptionSelections();
+ //CustomOption.ShareOptionSelections();
CustomOption.saveVanillaOptions();
}
}
}
- [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
{
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();
|| __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)
}
}
- [HarmonyPatch(typeof(StringOption), nameof(StringOption.OnEnable))]
+ [HarmonyPatch(typeof(StringOption), nameof(StringOption.Initialize))]
[HarmonyPostfix]
public static void Postfix(StringOption __instance)
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;
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);
// 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;
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>();
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;
}
}
}
public Transform Transform;
public SpriteRenderer Renderer;
public PlayerControl Owner;
- public GameData.PlayerInfo Data;
+ public NetworkedPlayerInfo Data;
public float Lifetime;
public Footprint() {
public Silhouette(Vector3 p, float duration = 1f, bool visibleForEveryOne = true) {
if (duration <= 0f) {
- TheOtherRolesPlugin.Logger.LogMessage("silhouette: permanent!");
permanent = true;
}
this.visibleForEveryOne = visibleForEveryOne;
}
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);
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;
[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
-using HarmonyLib;
+using AmongUs.GameOptions;
+using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Net.Http;
{
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";
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();
}
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;
// 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;
}
// 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));
}
}
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);
}
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;
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)))}";
}
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;
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);
}
[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
}
}
- 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;
if (CachedPlayer.LocalPlayer != null) {
Helpers.shareGameVersion();
}
+ GameStartManagerUpdatePatch.sendGamemode = true;
}
}
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
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>";
}
}
}
-
// 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();
}
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) {
}
__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())
// 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;
}
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;
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;
}
}
}
// 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)) {
--- /dev/null
+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;
+ }
+ }
+}
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);
}
}
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);
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;
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;
[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) ||
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) {
[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;
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;
[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) {
[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;
{
private static TextBoxTMP ipField;
private static TextBoxTMP portField;
+ private static GameObject serverWarning;
public static void Postfix(RegionMenu __instance) {
if (!__instance.TryCast<RegionMenu>()) return;
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);
+ }
+
}
}
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
}
}
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() {
assignRoleTargets(data); // Assign targets for Lawyer & Prosecutor
if (isGuesserGamemode) assignGuesserGamemode();
assignModifiers(); // Assign modifier
- setRolesAgain();
+ //setRolesAgain();
}
public static RoleAssignmentData getRoleAssignmentData() {
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);
{
[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:
[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;
[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);
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) {
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)
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)
CachedPlayer.PlayerPtrs.Remove(__instance.Pointer);
}
- [HarmonyPatch(typeof(GameData), nameof(GameData.Deserialize))]
+ [HarmonyPatch(typeof(NetworkedPlayerInfo), nameof(NetworkedPlayerInfo.Deserialize))]
[HarmonyPostfix]
public static void AddCachedDataOnDeserialize()
{
using AmongUs.Data;
using AmongUs.GameOptions;
using Assets.CoreScripts;
+using Reactor.Utilities.Extensions;
namespace TheOtherRoles
{
public enum RoleId {
{
// Main Controls
- ResetVaribles = 60,
+ ResetVaribles = 100,
ShareOptions,
ForceEnd,
WorkaroundSetRoles,
// Role functionality
- EngineerFixLights = 101,
+ EngineerFixLights = 120,
EngineerFixSubmergedOxygen,
EngineerUsedRepair,
CleanBody,
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);
{
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;
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) {
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;
case RoleId.Portalmaker:
Portalmaker.portalmaker = player;
break;
- case RoleId.Engineer:
+ case RoleId.Engineer:
Engineer.engineer = player;
break;
case RoleId.Sheriff:
}
if (AmongUsClient.Instance.AmHost && Helpers.roleCanUseVents(player) && !player.Data.Role.IsImpostor) {
player.RpcSetRole(RoleTypes.Engineer);
- player.SetRole(RoleTypes.Engineer);
+ player.CoSetRole(RoleTypes.Engineer, true);
}
}
}
}
}
+ 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) {
if (MeetingHudPatch.guesserUI != null) MeetingHudPatch.guesserUIExitButton.OnClick.Invoke();
}
Lawyer.lawyer.Exiled();
+ lawyerDiedAdditionally = true;
+ GameHistory.overrideDeathReasonAndKiller(Lawyer.lawyer, DeadPlayer.CustomDeathReason.LawyerSuicide, guesser);
}
dyingTarget.Exiled();
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;
}
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);
[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 &&
<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>
</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>
<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>
"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"