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