From 0d9e4d11c7bf530e69f2520493784682fe38dfdc Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Tue, 21 Jul 2026 16:27:34 +0200 Subject: [PATCH] some fixes --- Modules/FixedUpdateCaller.cs | 19 ++++++++++----- Modules/OptionHolder.cs | 7 ++++++ Modules/RPC.cs | 12 ++++++++++ Patches/ChatCommandPatch.cs | 7 ++++++ Patches/PlayerControlPatch.cs | 2 +- Resources/Lang/en_US.json | 2 ++ Roles/Standard/Addons/Common/Committed.cs | 24 +++++++++++++++++++ .../Crewmate/Investigate/Inquisitor.cs | 22 ++++++++++------- .../Crewmate/Investigate/Markseeker.cs | 6 +++++ Roles/Standard/Crewmate/Power/President.cs | 12 +++++++--- Roles/Standard/Ghost/Haunter.cs | 23 +++++++++++++----- Roles/Standard/Neutral/Pariah/Curser.cs | 9 ++++++- 12 files changed, 120 insertions(+), 25 deletions(-) diff --git a/Modules/FixedUpdateCaller.cs b/Modules/FixedUpdateCaller.cs index a086008fd..d4ead344c 100644 --- a/Modules/FixedUpdateCaller.cs +++ b/Modules/FixedUpdateCaller.cs @@ -67,16 +67,23 @@ public static class FixedUpdateCaller HudSpritePatch.Postfix(HudManager); ChatBubbleShower.Update(); - if (ChatUpdatePatch.LastMessages.Count > 0) + try { - long now = Utils.TimeStamp; - - for (var i = ChatUpdatePatch.LastMessages.Count - 1; i >= 0; i--) + if (ChatUpdatePatch.LastMessages.Count > 0) { - if (now - ChatUpdatePatch.LastMessages[i].SendTimeStamp > 10) - ChatUpdatePatch.LastMessages.RemoveAt(i); + long now = Utils.TimeStamp; + + for (var i = ChatUpdatePatch.LastMessages.Count - 1; i >= 0; i--) + { + if (now - ChatUpdatePatch.LastMessages[i].SendTimeStamp > 10) + ChatUpdatePatch.LastMessages.RemoveAt(i); + } } } + catch + { + ChatUpdatePatch.LastMessages.Clear(); + } } try { DataFlagRateLimiter.OnFixedUpdate(); } diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index b0a4928ac..a7481afc9 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -730,6 +730,7 @@ public static class Options public static OptionItem DisablePlayerVotedMessage; // Game Commands + public static OptionItem EnableAnagramCommand; public static OptionItem AnagramLanguage; public static OptionItem AnagramWordLength; public static OptionItem AnagramDifficulty; @@ -3018,6 +3019,9 @@ public static class Options .SetHeader(true) .SetColor(new Color32(100, 220, 255, byte.MaxValue)); + EnableAnagramCommand = new BooleanOptionItem(23820, "EnableAnagramCommand", true, TabGroup.GameSettings) + .SetColor(new Color32(100, 220, 255, byte.MaxValue)); + AnagramLanguage = new StringOptionItem(23821, "AnagramLanguage", [ "AnagramLang.Auto", "AnagramLang.English", @@ -3029,6 +3033,7 @@ public static class Options "AnagramLang.BrazilianPortuguese", "AnagramLang.Romanian" ], 0, TabGroup.GameSettings) + .SetParent(EnableAnagramCommand) .SetColor(new Color32(100, 220, 255, byte.MaxValue)); AnagramWordLength = new StringOptionItem(23822, "AnagramWordLength", [ @@ -3036,6 +3041,7 @@ public static class Options "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" ], 0, TabGroup.GameSettings, noTranslation: true) + .SetParent(EnableAnagramCommand) .SetColor(new Color32(100, 220, 255, byte.MaxValue)); AnagramDifficulty = new StringOptionItem(23823, "AnagramDifficulty", [ @@ -3045,6 +3051,7 @@ public static class Options "AnagramDiff.MediumHard", "AnagramDiff.Hard" ], 0, TabGroup.GameSettings) + .SetParent(EnableAnagramCommand) .SetColor(new Color32(100, 220, 255, byte.MaxValue)); diff --git a/Modules/RPC.cs b/Modules/RPC.cs index cec2ef99d..214b48daf 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -164,6 +164,8 @@ public enum CustomRPC Necronomicon, Stained, Entombed, + Committed, + Haunter, CTA, // Game Modes @@ -1385,6 +1387,16 @@ internal static class RPCHandlerPatch Entombed.ReceiveRPC(reader); break; } + case CustomRPC.Committed: + { + Committed.ReceiveRPC(reader); + break; + } + case CustomRPC.Haunter: + { + Haunter.ReceiveRPC(reader); + break; + } case CustomRPC.CTA: { CustomTeamManager.ReceiveRPC(reader); diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index beb4b4796..813acecee 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -990,6 +990,7 @@ internal static class ChatCommands ms.MarkedId = args.Length < 2 ? byte.MaxValue : byte.TryParse(args[1], out byte targetId) ? targetId : byte.MaxValue; player.RPCPlayCustomSound("Line"); + Utils.SendRPC(CustomRPC.SyncRoleData, player.PlayerId, ms.MarkedId); MeetingManager.SendCommandUsedMessage(args[0]); } @@ -1259,6 +1260,12 @@ internal static class ChatCommands private static void AnagramCommand(PlayerControl player, string text, string[] args) { + if (!Options.EnableAnagramCommand.GetBool()) + { + Utils.SendMessage("\n", player.PlayerId, GetString("AnagramDisabled"), importance: MessageImportance.Low); + return; + } + string langParam = GetLangParam(); int lengthIndex = Options.AnagramWordLength.GetValue(); int wordLength = lengthIndex == 0 ? 0 : lengthIndex + 1; diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index 0fb6cfeb3..40132e770 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -21,7 +21,7 @@ internal static class CheckProtectPatch { public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target) { - if (!AmongUsClient.Instance.AmHost || target.Data.IsDead || !target.IsAlive()) return false; + if (!AmongUsClient.Instance.AmHost || AntiBlackout.SkipTasks || target.Data.IsDead || !target.IsAlive()) return false; Logger.Info($"CheckProtect: {__instance.GetNameWithRole()} => {target.GetNameWithRole()}", "CheckProtect"); diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index 3867cc912..0f74824fe 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -8960,6 +8960,7 @@ "WhenSkipVoteIgnoreNoDeadBody": "Ignore When No Dead Body", "WhenSkipVoteIgnoreEmergency": "Ignore at Emergency Meetings", "MenuTitle.GameCommands": "Game Commands", + "EnableAnagramCommand": "Enable use of /anagram", "AnagramLanguage": "Anagram Word Language", "AnagramLang.Auto": "Auto (System Language)", "AnagramLang.English": "English", @@ -10366,6 +10367,7 @@ "AlliesKnowCrewpostor": "Known to Impostors", "AmOblivious": "You are Oblivious, meaning you cannot report bodies", "Anagram": "The scrambled word is {0}! Guess the original word! (Hint: It starts with the letter {1}!)", + "AnagramDisabled": "<#ff0000>X The /anagram command is disabled in this lobby.", "AnalyzeCD": "Analyze Cooldown", "AnalyzeDur": "Analyze Duration", "AnalyzerCD": "Analyze Cooldown", diff --git a/Roles/Standard/Addons/Common/Committed.cs b/Roles/Standard/Addons/Common/Committed.cs index dc85132a9..ee15f9560 100644 --- a/Roles/Standard/Addons/Common/Committed.cs +++ b/Roles/Standard/Addons/Common/Committed.cs @@ -1,5 +1,7 @@ using System.Collections.Generic; using System.Linq; +using EHR.Modules; +using Hazel; namespace EHR.Roles; @@ -43,6 +45,7 @@ public class Committed : IAddon ReduceKCD = null; var aapc = Main.CachedAlivePlayerControls(); + var doRPC = false; foreach (PlayerControl pc in aapc) { @@ -50,8 +53,23 @@ public class Committed : IAddon { Target ??= []; Target[pc.PlayerId] = aapc.Where(x => !x.Is(CustomRoles.Committed)).RandomElement().PlayerId; + if (pc.IsNonHostModdedClient()) doRPC = true; } } + + if (doRPC) + { + var writer = Utils.CreateRPC(CustomRPC.Committed); + writer.WritePacked(Target.Count); + + foreach ((byte key, byte value) in Target) + { + writer.Write(key); + writer.Write(value); + } + + Utils.EndRPC(writer); + } } public static void OnVotingResultsShown(List vs) @@ -77,4 +95,10 @@ public class Committed : IAddon if (!seer.Is(CustomRoles.Committed) || Target == null || !Target.TryGetValue(seer.PlayerId, out byte t) || t != target.PlayerId) return string.Empty; return CustomRoles.Committed.ColoredTextByRole("⌆"); } + + public static void ReceiveRPC(MessageReader reader) + { + Target = []; + Loop.Times(reader.ReadPackedInt32(), _ => Target[reader.ReadByte()] = reader.ReadByte()); + } } \ No newline at end of file diff --git a/Roles/Standard/Crewmate/Investigate/Inquisitor.cs b/Roles/Standard/Crewmate/Investigate/Inquisitor.cs index 6ceb8aab5..c0b7b8f9d 100644 --- a/Roles/Standard/Crewmate/Investigate/Inquisitor.cs +++ b/Roles/Standard/Crewmate/Investigate/Inquisitor.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; namespace EHR.Roles; @@ -39,19 +38,26 @@ public class Inquisitor : RoleBase public override bool OnVote(PlayerControl voter, PlayerControl target) { if (Starspawn.IsDayBreak) return false; - if (voter == null || target == null || voter.PlayerId == target.PlayerId || Main.DontCancelVoteList.Contains(voter.PlayerId)) return false; + if (!voter || !target || voter.PlayerId == target.PlayerId || Main.DontCancelVoteList.Contains(voter.PlayerId)) return false; + + var players = ExcludeDeadPlayers.GetBool() ? Main.CachedAlivePlayerControls() : Main.CachedAllPlayerControls(); + List<(byte Id, CustomRoles Role)> knownRoles = []; + + for (int index = 0; index < players.Count; index++) + { + var pc = players[index]; + if (Utils.KnowsTargetRole(target, pc)) + knownRoles.Add((pc.PlayerId, pc.GetCustomRole())); + } - var players = ExcludeDeadPlayers.GetBool() ? Main.EnumerateAlivePlayerControls() : Main.EnumeratePlayerControls(); - List<(byte Id, CustomRoles Role)> knownRoles = [.. from pc in players where Utils.KnowsTargetRole(target, pc) select (pc.PlayerId, pc.GetCustomRole())]; - string result; - if (knownRoles.Count == 0) + if (knownRoles.Count <= 1) result = Translator.GetString("InquisitorNoInfo"); else if (KnowExactRolesAfterTasksFinished.GetBool() && voter.GetTaskState().IsTaskFinished) - result = string.Join('\n', knownRoles.Select(x => $"{x.Id.ColoredPlayerName()}: {x.Role.ToColoredString()}")); + result = string.Join('\n', knownRoles.ConvertAll(x => $"{x.Id.ColoredPlayerName()}: {x.Role.ToColoredString()}")); else - result = string.Join(", ", knownRoles.Select(x => x.Id.ColoredPlayerName())); + result = string.Join(", ", knownRoles.ConvertAll(x => x.Id.ColoredPlayerName())); Utils.SendMessage("\n", voter.PlayerId, string.Format(Translator.GetString("InquisitorVoteResult"), target.PlayerId.ColoredPlayerName(), result), importance: MessageImportance.High); diff --git a/Roles/Standard/Crewmate/Investigate/Markseeker.cs b/Roles/Standard/Crewmate/Investigate/Markseeker.cs index 0d8adda66..d15bfbda6 100644 --- a/Roles/Standard/Crewmate/Investigate/Markseeker.cs +++ b/Roles/Standard/Crewmate/Investigate/Markseeker.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System; +using Hazel; using UnityEngine; namespace EHR.Roles; @@ -39,6 +40,11 @@ internal class Markseeker : RoleBase PlayerIdList = null; } + public void ReceiveRPC(MessageReader reader) + { + MarkedId = reader.ReadByte(); + } + /* public override bool OnVote(PlayerControl player, PlayerControl target) { diff --git a/Roles/Standard/Crewmate/Power/President.cs b/Roles/Standard/Crewmate/Power/President.cs index 5c745d5ce..b0ea71d50 100644 --- a/Roles/Standard/Crewmate/Power/President.cs +++ b/Roles/Standard/Crewmate/Power/President.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Linq; using AmongUs.GameOptions; +using EHR.Modules; using EHR.Patches; +using Hazel; namespace EHR.Roles; @@ -145,7 +147,7 @@ public class President : RoleBase return; } - if (!Utils.GetPlayerById(president.PresidentId).IsAlive()) return; + if (!pc.IsAlive()) return; if (!int.TryParse(message, out int num) || num is > 6 or < 1) { @@ -167,11 +169,10 @@ public class President : RoleBase { case Decree.Reveal: if (!DecreeSettings[decree][1].GetBool()) pc.RpcSetCustomRole(CustomRoles.Loyal); - if ((!DecreeSettings[decree][2].GetBool() && pc.IsConverted()) || pc.Is(CustomRoles.Bloodlust)) return; - Utils.SendMessage(string.Format(Translator.GetString("President.UsedDecreeMessage.Everyone"), Translator.GetString($"President.Decree.{decree}")), importance: MessageImportance.High); Utils.SendMessage(string.Format(Translator.GetString("President.UsedDecreeMessage.RevealMessage"), pc.PlayerId.ColoredPlayerName()), importance: MessageImportance.High); + Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId); break; case Decree.Finish: MeetingHudRpcClosePatch.AllowClose = true; @@ -264,4 +265,9 @@ public class President : RoleBase { OnVote(shapeshifter, target); } + + public void ReceiveRPC(MessageReader reader) + { + UsedDecrees.Add(Decree.Reveal); + } } \ No newline at end of file diff --git a/Roles/Standard/Ghost/Haunter.cs b/Roles/Standard/Ghost/Haunter.cs index 85e655875..e05004e05 100644 --- a/Roles/Standard/Ghost/Haunter.cs +++ b/Roles/Standard/Ghost/Haunter.cs @@ -2,6 +2,7 @@ using System.Linq; using AmongUs.GameOptions; using EHR.Modules; +using Hazel; namespace EHR.Roles; @@ -114,8 +115,7 @@ internal class Haunter : IGhostRole for (var i = 0; i < numOfReveals; i++) { - int index = IRandom.Instance.Next(WarnedImps.Count); - byte target = WarnedImps[index]; + byte target = WarnedImps.RandomElement(); targets.Add(target); WarnedImps.Remove(target); TargetArrow.Remove(target, pc.PlayerId); @@ -125,10 +125,18 @@ internal class Haunter : IGhostRole var targetPcs = targets.ToValidPlayers().ToArray(); - targetPcs.Do(x => x.Notify(Translator.GetString("HaunterRevealedYou"), 10f)); - WarnedImps.ToValidPlayers().Do(x => x.Notify(Translator.GetString("HaunterFinishedTasks"), 10f)); + targetPcs.NotifyPlayers(Translator.GetString("HaunterRevealedYou"), 10f, setName: false); + WarnedImps.ToValidPlayers().NotifyPlayers(Translator.GetString("HaunterFinishedTasks"), 10f); targetPcs.Do(x => Utils.NotifyRoles(SpecifyTarget: x)); + + if (Utils.DoRPC) + { + var writer = Utils.CreateRPC(CustomRPC.Haunter); + writer.WritePacked(targets.Count); + Loop.Times(targets.Count, i => writer.Write(targets[i])); + Utils.EndRPC(writer); + } } public void Update(PlayerControl pc) @@ -171,8 +179,6 @@ internal class Haunter : IGhostRole { if (role.Instance is not Haunter haunter) continue; - if (!haunter.WarnedImps.Contains(seer.PlayerId)) continue; - return TargetArrow.GetArrows(seer, haunter.HaunterId); } @@ -188,4 +194,9 @@ internal class Haunter : IGhostRole _ => true }; } + + public static void ReceiveRPC(MessageReader reader) + { + Loop.Times(reader.ReadPackedInt32(), _ => AllHauntedPlayers.Add(reader.ReadByte())); + } } \ No newline at end of file diff --git a/Roles/Standard/Neutral/Pariah/Curser.cs b/Roles/Standard/Neutral/Pariah/Curser.cs index 48390db7a..5f83f4983 100644 --- a/Roles/Standard/Neutral/Pariah/Curser.cs +++ b/Roles/Standard/Neutral/Pariah/Curser.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using System.Linq; using AmongUs.GameOptions; +using EHR.Modules; +using Hazel; namespace EHR.Roles; @@ -18,7 +20,6 @@ public class Curser : RoleBase public HashSet KnownFactionPlayers = []; private HashSet LowerSpeedPlayers = []; - private HashSet LowerVisionPlayers = []; public override bool IsEnable => On; @@ -80,6 +81,7 @@ public class Curser : RoleBase if (killer.CheckDoubleTrigger(target, () => { KnownFactionPlayers.Add(target.PlayerId); + Utils.SendRPC(CustomRPC.SyncRoleData, killer.PlayerId, target.PlayerId); Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); killer.SetKillCooldown(); killer.RpcRemoveAbilityUse(); @@ -150,4 +152,9 @@ public class Curser : RoleBase LowerSpeedPlayers.Clear(); players.Do(x => x.MarkDirtySettings()); } + + public void ReceiveRPC(MessageReader reader) + { + KnownFactionPlayers.Add(reader.ReadByte()); + } } \ No newline at end of file