From ef8febf979b15be4b29a5c510b986edb70211db5 Mon Sep 17 00:00:00 2001 From: Ape <155788660+ApeMV@users.noreply.github.com> Date: Mon, 12 Jan 2026 00:29:40 +0100 Subject: [PATCH] v1.1.0 - Fixes, Speedrun GM, Moderators, Commands, Yeah it's a lot --- AmongUsRevamped.cs | 2 +- Modules/CustomOptionsHolder.cs | 12 +- Modules/FixedUpdate.cs | 17 ++- Modules/Utils.cs | 11 +- Patches/ChatPatches.cs | 116 ++++++++++++++++++ Patches/CredentialsPatch.cs | 1 + Patches/EndGamePatches.cs | 5 +- Patches/JoinAndLeavePatches.cs | 4 + Patches/NumberOptionsPatch.cs | 2 + Patches/OnGameStartedPatch.cs | 21 +++- Patches/PlayerControlPatches.cs | 21 ++++ ...ChatControlPatch.cs => VotekickPatches.cs} | 18 --- 12 files changed, 203 insertions(+), 27 deletions(-) create mode 100644 Patches/ChatPatches.cs rename Patches/{ChatControlPatch.cs => VotekickPatches.cs} (70%) diff --git a/AmongUsRevamped.cs b/AmongUsRevamped.cs index d2c19d1..b632346 100644 --- a/AmongUsRevamped.cs +++ b/AmongUsRevamped.cs @@ -29,7 +29,7 @@ public partial class Main : BasePlugin public static NormalGameOptionsV10 NormalOptions => GameOptionsManager.Instance != null ? GameOptionsManager.Instance.currentNormalGameOptions : null; public static bool HasArgumentException; public static string CredentialsText; - public const string ModVersion = "v1.0.0"; + public const string ModVersion = "v1.1.0"; public static float GameTimer; diff --git a/Modules/CustomOptionsHolder.cs b/Modules/CustomOptionsHolder.cs index 15aa589..eaf7fb0 100644 --- a/Modules/CustomOptionsHolder.cs +++ b/Modules/CustomOptionsHolder.cs @@ -23,7 +23,7 @@ namespace AmongUsRevamped public static readonly string[] gameModes = { - "None", "0 Kill Cooldown", "Shift And Seek" + "None", "0 Kill Cooldown", "Shift And Seek", "Speedrun" }; //System @@ -174,6 +174,10 @@ namespace AmongUsRevamped public static OptionItem CantKillTime; public static OptionItem MisfiresToSuicide; + public static OptionItem TabGroupSpeedrun; + public static OptionItem SpeedrunSettingsOverride; + public static OptionItem GameAutoEndsAfter; + public static bool IsLoaded = false; @@ -232,6 +236,12 @@ namespace AmongUsRevamped CrewAutoWinsGameAfter = IntegerOptionItem.Create(70054, "Crewmates Automatically Win After", new(0, 600, 10), 300, TabGroup.GamemodeSettings, false) .SetValueFormat(OptionFormat.Seconds); + TabGroupSpeedrun = TextOptionItem.Create(70075, "Speedrun", TabGroup.GamemodeSettings) + .SetColor(Color.blue); + SpeedrunSettingsOverride = BooleanOptionItem.Create(70076, "Auto Update Settings", true, TabGroup.GamemodeSettings, false); + GameAutoEndsAfter = IntegerOptionItem.Create(70077, "Game automatically ends after", new(0, 600, 10), 300, TabGroup.GamemodeSettings, false) + .SetValueFormat(OptionFormat.Seconds); + // Gameplay Settings DisableSabotage = BooleanOptionItem.Create(60565, "Disable Critical Sabotages", false, TabGroup.ModSettings, false) diff --git a/Modules/FixedUpdate.cs b/Modules/FixedUpdate.cs index a2d9583..884d9d6 100644 --- a/Modules/FixedUpdate.cs +++ b/Modules/FixedUpdate.cs @@ -36,10 +36,25 @@ public static class FixedUpdate { Main.GameTimer = 0f; + MessageWriter writer = AmongUsClient.Instance.StartEndGame(); + writer.Write((byte)GameOverReason.ImpostorDisconnect); + AmongUsClient.Instance.FinishEndGame(writer); + Logger.Info($" Crewmates won because the game took longer than {Options.CrewAutoWinsGameAfter.GetInt()}s", "SNSManager"); + } + } + // 3 = Speedrun + if (Options.Gamemode.GetValue() == 3 && !Utils.isHideNSeek && Options.GameAutoEndsAfter.GetInt() != 0 && !Options.NoGameEnd.GetBool()) + { + Main.GameTimer += Time.fixedDeltaTime; + + if (Main.GameTimer > Options.GameAutoEndsAfter.GetInt()) + { + Main.GameTimer = 0f; + MessageWriter writer = AmongUsClient.Instance.StartEndGame(); writer.Write((byte)GameOverReason.CrewmatesByVote); AmongUsClient.Instance.FinishEndGame(writer); - Logger.Info($" Crewmates win because the game took longer than {Options.CrewAutoWinsGameAfter.GetInt()}s", "SNSManager"); + Logger.Info($" No one won because the game took longer than {Options.GameAutoEndsAfter.GetInt()}s", "SpeedrunManager"); } } } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 263d74d..69de414 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -35,6 +35,8 @@ public static class Utils public static bool IsFreePlay => AmongUsClient.Instance.NetworkMode == NetworkModes.FreePlay; public static bool IsMeeting => InGame && (MeetingHud.Instance); + public static bool GamePastRoleSelection => Main.GameTimer > 10f; + public static bool HandlingGameEnd; public static string ColorString(Color32 color, string str) => $"<#{color.r:x2}{color.g:x2}{color.b:x2}{color.a:x2}>{str}"; public static string ColorToHex(Color32 color) => $"#{color.r:x2}{color.g:x2}{color.b:x2}{color.a:x2}"; @@ -43,7 +45,7 @@ public static class Utils { if (friendCode == "") return false; - var friendCodesFilePath = @"./AUR-DATA/Moderators.txt"; + var friendCodesFilePath = @"./AUR-DATA/ModeratorList.txt"; var friendCodes = File.ReadAllLines(friendCodesFilePath); return friendCodes.Any(code => code.Contains(friendCode)); } @@ -63,6 +65,11 @@ public static class Utils } } + public static bool IsCustomOption(NumberOption option) + { + return option.GetComponent() != null; + } + public static void DestroyTranslator(this GameObject obj) { var translator = obj.GetComponent(); @@ -164,4 +171,4 @@ public static class Utils try { return AmongUsClient.Instance.allClients.ToArray().FirstOrDefault(cd => cd.Id == id); } catch { return null; } } -} +} \ No newline at end of file diff --git a/Patches/ChatPatches.cs b/Patches/ChatPatches.cs new file mode 100644 index 0000000..6619a49 --- /dev/null +++ b/Patches/ChatPatches.cs @@ -0,0 +1,116 @@ +using Hazel; +using InnerNet; +using System; +using UnityEngine; + +// https://github.com/SuperNewRoles/SuperNewRoles/blob/master/SuperNewRoles/Patches/LobbyBehaviourPatch.cs +namespace AmongUsRevamped; + +[HarmonyPatch(typeof(ChatController), nameof(ChatController.Update))] +internal static class ChatControllerUpdatePatch +{ + + public static void Postfix(ChatController __instance) + { + if (Main.DarkTheme.Value) + { + __instance.freeChatField.background.color = new Color32(40, 40, 40, byte.MaxValue); + + __instance.quickChatField.background.color = new Color32(40, 40, 40, byte.MaxValue); + __instance.quickChatField.text.color = Color.white; + } + else __instance.freeChatField.textArea.outputText.color = Color.black; + } +} + +[HarmonyPatch(typeof(ChatController), nameof(ChatController.SendChat))] +internal static class SendChatPatch +{ + public static bool Prefix(ChatController __instance) + { + string text = __instance.freeChatField.textArea.text.Trim(); + + if (text == "/h" || text == "/help") + { +// PlayerControl.LocalPlayer.SendChat("All AUR commands:\n/0kc - Sends the 0 Kill Cooldown gamemode description to everyone"); + return false; + } + + if (__instance.timeSinceLastMessage < 3f) return false; + + if (text == "/0kc" || text == "/0kcd" || text == "/0killcooldown") + { + PlayerControl.LocalPlayer.RpcSendChat("0 Kill Cooldown Mode:\n\nImpostors have no kill cooldown, Crewmates have low tasks.\nThink fast and pay attention."); + __instance.timeSinceLastMessage = 0.8f; + __instance.freeChatField.textArea.Clear(); + __instance.freeChatField.textArea.SetText(string.Empty); + return false; + } + + if (text == "/sns" || text == "/shiftandseek" || text == "/shift&seek") + { + PlayerControl.LocalPlayer.RpcSendChat("Shift and Seek Mode:\n\nImps can only kill someone while shapeshifted as them.\nSabotages & Meetings = Off."); + __instance.timeSinceLastMessage = 0.8f; + __instance.freeChatField.textArea.Clear(); + __instance.freeChatField.textArea.SetText(string.Empty); + + new LateTask(() => + { + PlayerControl.LocalPlayer.RpcSendChat($"Crew wins by tasks/surviving {Options.CrewAutoWinsGameAfter.GetInt()}s.\nImp wins by killing Crew.\n1 Wrong kill = Can't kill for {Options.CantKillTime.GetInt()}s.\n{Options.MisfiresToSuicide.GetInt()} Wrong kills = suicide."); + __instance.timeSinceLastMessage = 0.8f; + }, 2.2f, "SNSTutorial2"); + return false; + } + + if (text == "/sp" || text == "/sr" || text == "/speedrun") + { + PlayerControl.LocalPlayer.RpcSendChat($"Speedrun Mode:\n\nEveryone is a crewmate. The 1st player to finish tasks wins the game. Game auto ends after {Options.GameAutoEndsAfter.GetInt()}s"); + __instance.timeSinceLastMessage = 0.8f; + __instance.freeChatField.textArea.Clear(); + __instance.freeChatField.textArea.SetText(string.Empty); + return false; + } + + else return true; + } +} + +[HarmonyPatch(typeof(PlayerControl), "RpcSendChat")] +public static class PC_RpcSendChat +{ + // Banning works by Name and not Id + public static void Prefix(PlayerControl __instance, ref string chatText) + { + + if (!AmongUsClient.Instance.AmHost) + return; + + bool isKick = chatText.StartsWith("/kick "); + bool isBan = chatText.StartsWith("/ban "); + + if (!isKick && !isBan) + return; + + if (__instance == PlayerControl.LocalPlayer || Utils.IsPlayerModerator(__instance.Data.FriendCode)) + { + string kickedPlayerName = chatText.Substring(isBan ? 5 : 6).Trim(); + + PlayerControl target = null; + + foreach (PlayerControl p in PlayerControl.AllPlayerControls) + { + if (p.Data != null && !Utils.IsPlayerModerator(p.Data.FriendCode) && p != PlayerControl.LocalPlayer && p.Data.PlayerName.Equals(kickedPlayerName, StringComparison.OrdinalIgnoreCase)) + { + target = p; + break; + } + } + + if (target == null) + return; + + AmongUsClient.Instance.KickPlayer(target.Data.ClientId, isBan); + Logger.Info($" {__instance.Data.PlayerName} {(isBan ? "banned" : "kicked")} {target.Data.PlayerName}", "Kick&BanCommand"); + } + } +} \ No newline at end of file diff --git a/Patches/CredentialsPatch.cs b/Patches/CredentialsPatch.cs index 4bd046f..dc908fd 100644 --- a/Patches/CredentialsPatch.cs +++ b/Patches/CredentialsPatch.cs @@ -52,6 +52,7 @@ namespace AmongUsRevamped private static void Postfix(VersionShower __instance) { RpcSetTasksPatch.GlobalTaskIds = null; + Utils.HandlingGameEnd = false; OnGameJoinedPatch.AutoStartCheck = false; Main.GameTimer = 0f; MurderPlayerPatch.misfireCount.Clear(); diff --git a/Patches/EndGamePatches.cs b/Patches/EndGamePatches.cs index 5612139..3482f7f 100644 --- a/Patches/EndGamePatches.cs +++ b/Patches/EndGamePatches.cs @@ -11,6 +11,7 @@ public static class EndGameManagerPatch public static void Postfix(EndGameManager __instance) { RpcSetTasksPatch.GlobalTaskIds = null; + Utils.HandlingGameEnd = false; OnGameJoinedPatch.AutoStartCheck = false; Main.GameTimer = 0f; MurderPlayerPatch.misfireCount.Clear(); @@ -27,7 +28,7 @@ class NormalGameEndChecker { public static bool Prefix() { - if (Options.NoGameEnd.GetBool()) return false; + if (Options.NoGameEnd.GetBool() || Options.Gamemode.GetValue() == 3) return false; else return true; } } @@ -60,6 +61,6 @@ internal class ControllerManagerUpdatePatch } else PlayerControl.LocalPlayer.ReportDeadBody(PlayerControl.LocalPlayer.Data); - } + } } } \ No newline at end of file diff --git a/Patches/JoinAndLeavePatches.cs b/Patches/JoinAndLeavePatches.cs index b23bb58..f76d6ea 100644 --- a/Patches/JoinAndLeavePatches.cs +++ b/Patches/JoinAndLeavePatches.cs @@ -56,6 +56,10 @@ class OnPlayerJoinedPatch { BanManager.CheckBanPlayer(Client); + if (Utils.IsPlayerModerator(Client.FriendCode) && Options.ApplyModeratorList.GetBool()) + { + Logger.Info($" {Client.PlayerName} is moderator", "ModeratorCheck"); + } if (HasInvalidFriendCode(Client.FriendCode) && Options.KickInvalidFriendCodes.GetBool()) { diff --git a/Patches/NumberOptionsPatch.cs b/Patches/NumberOptionsPatch.cs index b68fdf9..4a10fcf 100644 --- a/Patches/NumberOptionsPatch.cs +++ b/Patches/NumberOptionsPatch.cs @@ -47,6 +47,8 @@ public static class NumberOption_Initialize { public static void Postfix(NumberOption __instance) { + if (ModGameOptionsMenu.TabIndex >= 3) return; + if (Utils.isHideNSeek || !Utils.isHideNSeek && __instance.Title != StringNames.GameNumImpostors && __instance.Title != StringNames.GamePlayerSpeed) { __instance.ValidRange = new FloatRange(-900f, 900f); diff --git a/Patches/OnGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs index 3ff749f..ec512cc 100644 --- a/Patches/OnGameStartedPatch.cs +++ b/Patches/OnGameStartedPatch.cs @@ -24,6 +24,23 @@ internal class ApplyCustomImpostorCount } } + if (Options.Gamemode.GetValue() == 3 && !Utils.isHideNSeek) + { + foreach (var p in PlayerControl.AllPlayerControls) + { + p.RpcSetRole(AmongUs.GameOptions.RoleTypes.Crewmate, false); + + new LateTask(() => + { + p.RpcSetRole(AmongUs.GameOptions.RoleTypes.Crewmate, false); + }, 5f, "Speedrun Secondary RPCSetRole"); + + new LateTask(() => + { + p.RpcSetRole(AmongUs.GameOptions.RoleTypes.Crewmate, false); + }, 9f, "Speedrun Tertiary RPCSetRole"); + } + } if (Utils.isHideNSeek) { @@ -61,12 +78,12 @@ internal class ApplyCustomImpostorCount new LateTask(() => { p.RpcSetRole(AmongUs.GameOptions.RoleTypes.Impostor, false); - }, 5f, "Secondary RPCSetRole"); + }, 5f, "HNS Secondary RPCSetRole"); new LateTask(() => { p.RpcSetRole(AmongUs.GameOptions.RoleTypes.Impostor, false); - }, 9f, "Tertairy RPCSetRole"); + }, 9f, "HNS Tertiary RPCSetRole"); } } } diff --git a/Patches/PlayerControlPatches.cs b/Patches/PlayerControlPatches.cs index 0a4393a..154148e 100644 --- a/Patches/PlayerControlPatches.cs +++ b/Patches/PlayerControlPatches.cs @@ -47,6 +47,27 @@ class FixedUpdateInGamePatch } } + // Speedrun + if (Options.Gamemode.GetValue() == 3 && !Utils.isHideNSeek) + { + Main.NormalOptions.NumEmergencyMeetings = 0; + + Main.NormalOptions.TaskBarMode = 0; + + if (__instance.AllTasksCompleted() && Utils.InGame && Utils.GamePastRoleSelection && !Utils.HandlingGameEnd) + { + Utils.HandlingGameEnd = true; + __instance.RpcSetRole(AmongUs.GameOptions.RoleTypes.ImpostorGhost, false); + + new LateTask(() => + { + MessageWriter writer = AmongUsClient.Instance.StartEndGame(); + writer.Write((byte)GameOverReason.ImpostorsByVote); + AmongUsClient.Instance.FinishEndGame(writer); + }, 1f, "SpeedrunSetWinner"); + } + } + if (Options.Gamemode.GetValue() == 0 && Main.NormalOptions.KillCooldown <= 0.01f) { Main.NormalOptions.KillCooldown = 25f; diff --git a/Patches/ChatControlPatch.cs b/Patches/VotekickPatches.cs similarity index 70% rename from Patches/ChatControlPatch.cs rename to Patches/VotekickPatches.cs index 794c2fd..065acdc 100644 --- a/Patches/ChatControlPatch.cs +++ b/Patches/VotekickPatches.cs @@ -3,26 +3,8 @@ using InnerNet; using System; using UnityEngine; -// https://github.com/SuperNewRoles/SuperNewRoles/blob/master/SuperNewRoles/Patches/LobbyBehaviourPatch.cs namespace AmongUsRevamped; -[HarmonyPatch(typeof(ChatController), nameof(ChatController.Update))] -internal static class ChatControllerUpdatePatch -{ - - public static void Postfix(ChatController __instance) - { - if (Main.DarkTheme.Value) - { - __instance.freeChatField.background.color = new Color32(40, 40, 40, byte.MaxValue); - - __instance.quickChatField.background.color = new Color32(40, 40, 40, byte.MaxValue); - __instance.quickChatField.text.color = Color.white; - } - else __instance.freeChatField.textArea.outputText.color = Color.black; - } -} - [HarmonyPatch(typeof(VoteBanSystem), nameof(VoteBanSystem.AddVote))] internal static class AddVotePatch {