From c9104e9c0ee0893f0e1e6ad43a4a17d1a1d08c5d Mon Sep 17 00:00:00 2001 From: TommyXL <104814436+Tommy-XL@users.noreply.github.com> Date: Thu, 20 Aug 2026 15:43:54 +0800 Subject: [PATCH] Support 2026.8.18 (#677) * Support 2026.8.18 * Huh * Add Judge in settings * OptionsV10 => OptionsV11 * Fix MeetingHudCastVotePatch * Opss * JudgeOld in string --- CTA/CustomTeamAssigner/CustomRoles.cs | 4 +- CustomRoles.cs | 4 +- EHR.csproj | 4 +- Main.cs | 20 +- Modules/AURoleOptions.cs | 6 + Modules/CustomRoleSelector.cs | 4 +- Modules/CustomRolesHelper.cs | 10 +- Modules/EAC.cs | 32 +-- Modules/ExtendedPlayerControl.cs | 2 +- Modules/Extensions/IGameManagerEx.cs | 20 +- .../GameOptionsSender/GameOptionsSender.cs | 8 +- .../PlayerGameOptionsSender.cs | 5 +- Modules/GameState.cs | 4 +- Modules/GuessManager.cs | 36 ++-- Modules/OptionBackup/OptionBackupData.cs | 2 +- Modules/Utils.cs | 4 +- Patches/ChatCommandPatch.cs | 4 +- Patches/CheckGameEndPatch.cs | 1 + Patches/Crowded.cs | 6 +- Patches/HudPatch.cs | 2 +- Patches/HudSpritePatch.cs | 2 +- Patches/IntroPatch.cs | 9 +- Patches/MeetingHudPatch.cs | 186 ++++++++++-------- Patches/OnGameStartedPatch.cs | 7 +- Patches/PlayerControlPatch.cs | 7 +- Resources/Lang/en_US.json | 10 +- Roles/Standard/Coven/Summoner.cs | 4 +- .../Standard/Crewmate/Investigate/Analyst.cs | 1 + .../Standard/Crewmate/Investigate/Imitator.cs | 4 +- .../Standard/Crewmate/Investigate/Inquirer.cs | 4 +- .../Crewmate/Investigate/Inspector.cs | 4 +- .../Crewmate/Investigate/Markseeker.cs | 4 +- .../Crewmate/Investigate/MeetingManager.cs | 2 +- Roles/Standard/Crewmate/Killing/Judge.cs | 36 ++-- .../Crewmate/Killing/Retributionist.cs | 4 +- Roles/Standard/Crewmate/Power/CopyCat.cs | 2 +- Roles/Standard/Crewmate/Power/President.cs | 2 +- Roles/Standard/Crewmate/Power/Swapper.cs | 6 +- Roles/Standard/Crewmate/Support/Negotiator.cs | 2 +- .../Crewmate/Vanilla/CrewmateVanillaRoles.cs | 7 + Roles/Standard/Impostor/Concealing/Forger.cs | 4 +- Roles/Standard/Impostor/Killing/Assumer.cs | 4 +- Roles/Standard/Impostor/Killing/Councillor.cs | 6 +- Roles/Standard/Impostor/Killing/Nemesis.cs | 4 +- .../Impostor/Miscellaneous/Changeling.cs | 6 +- .../Standard/Impostor/Miscellaneous/Loner.cs | 4 +- Roles/Standard/Impostor/Support/Gangster.cs | 2 +- .../Impostor/Support/Ventriloquist.cs | 4 +- Roles/Standard/Neutral/Benign/Pawn.cs | 6 +- Roles/Standard/Neutral/Evil/Collector.cs | 4 +- 50 files changed, 292 insertions(+), 233 deletions(-) diff --git a/CTA/CustomTeamAssigner/CustomRoles.cs b/CTA/CustomTeamAssigner/CustomRoles.cs index 6310723e6..fe592aa48 100644 --- a/CTA/CustomTeamAssigner/CustomRoles.cs +++ b/CTA/CustomTeamAssigner/CustomRoles.cs @@ -144,6 +144,7 @@ public enum CustomRoles Scientist, Tracker, Detective, + Judge, // Vanilla Remakes CrewmateEHR, @@ -153,6 +154,7 @@ public enum CustomRoles ScientistEHR, TrackerEHR, DetectiveEHR, + JudgeEHR, // Crewmates @@ -224,7 +226,7 @@ public enum CustomRoles Inquisitor, Jailor, Journalist, - Judge, + JudgeOld, LazyGuy, Leery, Lighter, diff --git a/CustomRoles.cs b/CustomRoles.cs index 6310723e6..fe592aa48 100644 --- a/CustomRoles.cs +++ b/CustomRoles.cs @@ -144,6 +144,7 @@ public enum CustomRoles Scientist, Tracker, Detective, + Judge, // Vanilla Remakes CrewmateEHR, @@ -153,6 +154,7 @@ public enum CustomRoles ScientistEHR, TrackerEHR, DetectiveEHR, + JudgeEHR, // Crewmates @@ -224,7 +226,7 @@ public enum CustomRoles Inquisitor, Jailor, Journalist, - Judge, + JudgeOld, LazyGuy, Leery, Lighter, diff --git a/EHR.csproj b/EHR.csproj index 35d9c516f..b28e00f8d 100644 --- a/EHR.csproj +++ b/EHR.csproj @@ -33,9 +33,9 @@ - + - + diff --git a/Main.cs b/Main.cs index 00c82e16d..75e900d74 100644 --- a/Main.cs +++ b/Main.cs @@ -41,9 +41,9 @@ public class Main : BasePlugin private const string DebugKeyHash = "c0fd562955ba56af3ae20d7ec9e64c664f0facecef4b3e366e109306adeae29d"; private const string DebugKeySalt = "59687b"; public const string PluginGuid = "com.gurge44.endlesshostroles"; - public const string PluginVersion = "7.9.0"; - public const string PluginDisplayVersion = "7.9.0"; - public const bool TestBuild = false; + public const string PluginVersion = "7.9.1"; + public const string PluginDisplayVersion = "7.9.1 Test 1"; + public const bool TestBuild = true; public const string NeutralColor = "#ffab1b"; public const string ImpostorColor = "#ff1919"; @@ -57,7 +57,7 @@ public class Main : BasePlugin public const string ModColor = "#00ffff"; public const bool AllowPublicRoom = true; public const string ForkId = "EHR"; - public const string SupportedAUVersion = "2026.3.31"; + public const string SupportedAUVersion = "2026.8.18"; private static string StarData => Environment.GetEnvironmentVariable("STAR_DATA_PATH"); @@ -191,7 +191,7 @@ public class Main : BasePlugin public Harmony Harmony { get; } = new(PluginGuid); - public static NormalGameOptionsV10 NormalOptions => GameOptionsManager.Instance != null ? GameOptionsManager.Instance.currentNormalGameOptions : null; + public static NormalGameOptionsV11 NormalOptions => GameOptionsManager.Instance != null ? GameOptionsManager.Instance.currentNormalGameOptions : null; // Client Options public static ConfigEntry HideName { get; private set; } @@ -453,6 +453,7 @@ public class Main : BasePlugin { CustomRoles.Tracker, "#34ad50" }, { CustomRoles.Noisemaker, "#ff4a62" }, { CustomRoles.Detective, "#625EEE" }, + { CustomRoles.Judge, "#f8d85a" }, // Vanilla Remakes { CustomRoles.CrewmateEHR, "#8cffff" }, { CustomRoles.EngineerEHR, "#FF6A00" }, @@ -461,6 +462,7 @@ public class Main : BasePlugin { CustomRoles.TrackerEHR, "#34ad50" }, { CustomRoles.NoisemakerEHR, "#ff4a62" }, { CustomRoles.DetectiveEHR, "#625EEE" }, + { CustomRoles.JudgeEHR, "#f8d85a" }, // Crewmates { CustomRoles.DoubleAgent, "#ff1919" }, { CustomRoles.Luckey, "#b8d7a3" }, @@ -579,7 +581,7 @@ public class Main : BasePlugin { CustomRoles.Medic, "#00ff97" }, { CustomRoles.FortuneTeller, "#882c83" }, { CustomRoles.Glitch, "#39FF14" }, - { CustomRoles.Judge, "#f8d85a" }, + { CustomRoles.JudgeOld, "#f8d85a" }, { CustomRoles.Mortician, "#333c49" }, { CustomRoles.Medium, "#a200ff" }, { CustomRoles.Observer, "#a8e0fa" }, @@ -947,9 +949,9 @@ public class Main : BasePlugin ClassInjector.RegisterTypeInIl2Cpp(); ClassInjector.RegisterTypeInIl2Cpp(); - NormalGameOptionsV10.RecommendedImpostors = NormalGameOptionsV10.MaxImpostors = Enumerable.Repeat(128, 128).ToArray(); - NormalGameOptionsV10.MinPlayers = Enumerable.Repeat(4, 128).ToArray(); - HideNSeekGameOptionsV10.MinPlayers = Enumerable.Repeat(4, 128).ToArray(); + NormalGameOptionsV11.RecommendedImpostors = NormalGameOptionsV11.MaxImpostors = Enumerable.Repeat(128, 128).ToArray(); + NormalGameOptionsV11.MinPlayers = Enumerable.Repeat(4, 128).ToArray(); + HideNSeekGameOptionsV11.MinPlayers = Enumerable.Repeat(4, 128).ToArray(); PrivateTagManager.LoadTagsFromFile(); diff --git a/Modules/AURoleOptions.cs b/Modules/AURoleOptions.cs index e00464255..f961e4aa4 100644 --- a/Modules/AURoleOptions.cs +++ b/Modules/AURoleOptions.cs @@ -132,6 +132,12 @@ public static class AURoleOptions set => Opt.SetFloat(FloatOptionNames.DetectiveSuspectLimit, value); } + public static float JudgeTaskRequirementPercentage + { + get => Opt.GetFloat(FloatOptionNames.JudgeTaskRequirementPercentage); + set => Opt.SetFloat(FloatOptionNames.JudgeTaskRequirementPercentage, value); + } + public static void SetOpt(IGameOptions opt) { Opt = opt; diff --git a/Modules/CustomRoleSelector.cs b/Modules/CustomRoleSelector.cs index 242c2c7d1..3d8fc4414 100644 --- a/Modules/CustomRoleSelector.cs +++ b/Modules/CustomRoleSelector.cs @@ -20,7 +20,8 @@ internal static class CustomRoleSelector [RoleTypes.Tracker] = 0, [RoleTypes.Phantom] = 0, [RoleTypes.Viper] = 0, - [RoleTypes.Detective] = 0 + [RoleTypes.Detective] = 0, + [RoleTypes.Judge] = 0 }; public static readonly Dictionary GameModeRoles = new() @@ -523,6 +524,7 @@ internal static class CustomRoleSelector [RoleTypes.Phantom] = 0, [RoleTypes.Viper] = 0, [RoleTypes.Detective] = 0, + [RoleTypes.Judge] = 0, }; foreach (CustomRoles role in RoleResult.Values) diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index 9681cc9f8..8e3ccaa31 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -352,7 +352,7 @@ internal static class CustomRolesHelper CustomRoles.Hangman => CustomRoles.Shapeshifter, CustomRoles.Sunnyboy => CustomRoles.Scientist, CustomRoles.Specter => Options.PhantomCanVent.GetBool() ? CustomRoles.Engineer : CustomRoles.Crewmate, - CustomRoles.Judge => CustomRoles.Crewmate, + CustomRoles.JudgeOld => CustomRoles.Crewmate, CustomRoles.Councillor => CustomRoles.Impostor, CustomRoles.Mortician => CustomRoles.Crewmate, CustomRoles.Medium => CustomRoles.Crewmate, @@ -411,6 +411,7 @@ internal static class CustomRolesHelper CustomRoles.NoisemakerEHR => CustomRoles.Noisemaker, CustomRoles.DetectiveEHR => CustomRoles.Detective, CustomRoles.ViperEHR => CustomRoles.Viper, + CustomRoles.JudgeEHR => CustomRoles.Judge, // Hide And Seek CustomRoles.Hider => CustomRoles.Crewmate, @@ -468,6 +469,7 @@ internal static class CustomRolesHelper CustomRoles.Shapeshifter => CustomRoles.ShapeshifterEHR, CustomRoles.Detective => CustomRoles.DetectiveEHR, CustomRoles.Viper => CustomRoles.ViperEHR, + CustomRoles.Judge => CustomRoles.JudgeEHR, _ => role.IsImpostor() ? CustomRoles.ImpostorEHR : CustomRoles.CrewmateEHR }; } @@ -1368,6 +1370,8 @@ internal static class CustomRolesHelper CustomRoles.NoisemakerEHR => RoleOptionType.Crewmate_Miscellaneous, CustomRoles.Detective => RoleOptionType.Crewmate_Miscellaneous, CustomRoles.DetectiveEHR => RoleOptionType.Crewmate_Miscellaneous, + CustomRoles.Judge => RoleOptionType.Crewmate_Miscellaneous, + CustomRoles.JudgeEHR => RoleOptionType.Crewmate_Miscellaneous, CustomRoles.Addict => RoleOptionType.Crewmate_Miscellaneous, CustomRoles.CameraMan => RoleOptionType.Crewmate_Miscellaneous, CustomRoles.Carrier => RoleOptionType.Crewmate_Miscellaneous, @@ -1481,7 +1485,7 @@ internal static class CustomRolesHelper CustomRoles.Ventguard => RoleOptionType.Crewmate_Support, CustomRoles.Wizard => RoleOptionType.Crewmate_Support, CustomRoles.Drainer => RoleOptionType.Crewmate_Killing, - CustomRoles.Judge => RoleOptionType.Crewmate_Killing, + CustomRoles.JudgeOld => RoleOptionType.Crewmate_Killing, CustomRoles.NiceGuesser => RoleOptionType.Crewmate_Killing, CustomRoles.Retributionist => RoleOptionType.Crewmate_Killing, CustomRoles.Sentinel => RoleOptionType.Crewmate_Killing, @@ -1674,6 +1678,7 @@ internal static class CustomRolesHelper CustomRoles.GuardianAngel or CustomRoles.Impostor or CustomRoles.Detective or + CustomRoles.Judge or CustomRoles.Viper or CustomRoles.Phantom or CustomRoles.Shapeshifter; @@ -1689,6 +1694,7 @@ internal static class CustomRolesHelper CustomRoles.GuardianAngelEHR or CustomRoles.ImpostorEHR or CustomRoles.DetectiveEHR or + CustomRoles.JudgeEHR or CustomRoles.ViperEHR or CustomRoles.PhantomEHR or CustomRoles.ShapeshifterEHR; diff --git a/Modules/EAC.cs b/Modules/EAC.cs index c6fbd5e4d..47f44a098 100644 --- a/Modules/EAC.cs +++ b/Modules/EAC.cs @@ -87,7 +87,7 @@ internal static class EAC { byte targetId = sr.ReadByte(); - if (GameStates.IsMeeting && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating && !pc.IsHost()) + if (GameStates.IsMeeting && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating && !pc.IsHost()) { WarnHost(); Report(pc, "Report dead body in meeting"); @@ -119,7 +119,7 @@ internal static class EAC { bool bodyExists = Object.FindObjectsOfType().Any(deadBody => deadBody.ParentId == targetId); - if (!bodyExists && targetId != pc.PlayerId && (!MeetingHud.Instance || MeetingHud.Instance.state != MeetingHud.VoteStates.Animating)) + if (!bodyExists && targetId != pc.PlayerId && (!MeetingHud.Instance || MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating)) { Logger.Warn($"Player [{pc.OwnerId}:{pc.GetRealName()}] attempted to report a body that does't exist D", "EAC"); sr.Recycle(); @@ -283,7 +283,7 @@ internal static class EAC return true; } - if (((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) && target != pc && !(Options.UseMeetingShapeshift.GetBool() && (GuessManager.Data.ContainsKey(pc.PlayerId) || pc.UsesMeetingShapeshift()))) + if (((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) && target != pc && !(Options.UseMeetingShapeshift.GetBool() && (GuessManager.Data.ContainsKey(pc.PlayerId) || pc.UsesMeetingShapeshift()))) { WarnHost(); Report(pc, "Trying to shift during meeting"); @@ -340,7 +340,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating && !ReportDeadBodyPatch.MeetingStarted) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating && !ReportDeadBodyPatch.MeetingStarted) || ExileController.Instance) { WarnHost(); Report(pc, "Doing task during meeting"); @@ -390,7 +390,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "Trying to vanish during meeting"); @@ -412,7 +412,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "Trying to appear during meeting"); @@ -444,7 +444,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "PlayAnimation Rpc during meeting"); @@ -499,7 +499,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "SetScanner Rpc during meeting"); @@ -557,7 +557,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "Using platform during meeting"); @@ -591,7 +591,7 @@ internal static class EAC if (target == null) break; - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "Trying to protect during meeting"); @@ -623,7 +623,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "Using zipline during meeting"); @@ -655,7 +655,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(pc, "Triggering spore during meeting"); @@ -880,7 +880,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(player, "Venting during meeting"); @@ -954,7 +954,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(player, "Climbing ladder during meeting"); @@ -1010,7 +1010,7 @@ internal static class EAC return true; } - if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) || ExileController.Instance) + if ((MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) || ExileController.Instance) { WarnHost(); Report(player, "Petting during meeting"); @@ -1112,7 +1112,7 @@ internal static class EAC { if (player.IsModdedClient() || !AmongUsClient.Instance.AmHost) return false; - if (GameStates.IsMeeting && MeetingHud.Instance.state is MeetingHud.VoteStates.Voted or MeetingHud.VoteStates.NotVoted or MeetingHud.VoteStates.Discussion or MeetingHud.VoteStates.Proceeding) + if (GameStates.IsMeeting && MeetingHud.Instance.state is MeetingHud.MeetingStates.Voted or MeetingHud.MeetingStates.NotVoted or MeetingHud.MeetingStates.Discussion or MeetingHud.MeetingStates.Proceeding) { WarnHost(); Report(player, "Bad Sabotage D : In Meeting"); diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index b78bfab4d..98ea724be 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -57,7 +57,7 @@ internal static class ExtendedPlayerControl public bool UsesMeetingShapeshift() { CustomRoles role = player.GetCustomRole(); - // if (player.IsModdedClient() && role is CustomRoles.Councillor or CustomRoles.Inspector or CustomRoles.Judge or CustomRoles.Retributionist or CustomRoles.Starspawn or CustomRoles.Swapper or CustomRoles.Ventriloquist) return false; + // if (player.IsModdedClient() && role is CustomRoles.Councillor or CustomRoles.Inspector or CustomRoles.JudgeOld or CustomRoles.Retributionist or CustomRoles.Starspawn or CustomRoles.Swapper or CustomRoles.Ventriloquist) return false; return role.UsesMeetingShapeshift(); } diff --git a/Modules/Extensions/IGameManagerEx.cs b/Modules/Extensions/IGameManagerEx.cs index 208297cf5..bd279bde1 100644 --- a/Modules/Extensions/IGameManagerEx.cs +++ b/Modules/Extensions/IGameManagerEx.cs @@ -11,13 +11,13 @@ public static class IGameManagerEx opt.SetBool(name, value); } - public void Set(bool value, NormalGameOptionsV10 opt) + public void Set(bool value, NormalGameOptionsV11 opt) { if (name is not BoolOptionNames.GhostsDoTasks and not BoolOptionNames.Roles) opt.SetBool(name, value); } - public void Set(bool value, HideNSeekGameOptionsV10 opt) + public void Set(bool value, HideNSeekGameOptionsV11 opt) { opt.SetBool(name, value); } @@ -30,12 +30,12 @@ public static class IGameManagerEx opt.SetInt(name, value); } - public void Set(int value, NormalGameOptionsV10 opt) + public void Set(int value, NormalGameOptionsV11 opt) { opt.SetInt(name, value); } - public void Set(int value, HideNSeekGameOptionsV10 opt) + public void Set(int value, HideNSeekGameOptionsV11 opt) { opt.SetInt(name, value); } @@ -48,12 +48,12 @@ public static class IGameManagerEx opt.SetFloat(name, value); } - public void Set(float value, NormalGameOptionsV10 opt) + public void Set(float value, NormalGameOptionsV11 opt) { opt.SetFloat(name, value); } - public void Set(float value, HideNSeekGameOptionsV10 opt) + public void Set(float value, HideNSeekGameOptionsV11 opt) { opt.SetFloat(name, value); } @@ -66,12 +66,12 @@ public static class IGameManagerEx opt.SetByte(name, value); } - public void Set(byte value, NormalGameOptionsV10 opt) + public void Set(byte value, NormalGameOptionsV11 opt) { opt.SetByte(name, value); } - public void Set(byte value, HideNSeekGameOptionsV10 opt) + public void Set(byte value, HideNSeekGameOptionsV11 opt) { opt.SetByte(name, value); } @@ -84,12 +84,12 @@ public static class IGameManagerEx opt.SetUInt(name, value); } - public void Set(uint value, NormalGameOptionsV10 opt) + public void Set(uint value, NormalGameOptionsV11 opt) { opt.SetUInt(name, value); } - public void Set(uint value, HideNSeekGameOptionsV10 opt) + public void Set(uint value, HideNSeekGameOptionsV11 opt) { opt.SetUInt(name, value); } diff --git a/Modules/GameOptionsSender/GameOptionsSender.cs b/Modules/GameOptionsSender/GameOptionsSender.cs index 089d5d660..a124ae157 100644 --- a/Modules/GameOptionsSender/GameOptionsSender.cs +++ b/Modules/GameOptionsSender/GameOptionsSender.cs @@ -23,10 +23,10 @@ public abstract class GameOptionsSender writer.StartMessage(0); writer.Write((byte)currentGameMode); - if (opt.TryCast(out NormalGameOptionsV10 normalOpt)) - NormalGameOptionsV10.Serialize(writer, normalOpt); - else if (opt.TryCast(out HideNSeekGameOptionsV10 hnsOpt)) - HideNSeekGameOptionsV10.Serialize(writer, hnsOpt); + if (opt.TryCast(out NormalGameOptionsV11 normalOpt)) + NormalGameOptionsV11.Serialize(writer, normalOpt); + else if (opt.TryCast(out HideNSeekGameOptionsV11 hnsOpt)) + HideNSeekGameOptionsV11.Serialize(writer, hnsOpt); else Logger.Error("Option cast failed", ToString()); diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs index 367ac726e..0c1bef03e 100644 --- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs +++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs @@ -19,7 +19,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS public PlayerControl player = player; private static IGameOptions BasedGameOptions => - Main.RealOptionsData.Restore(new NormalGameOptionsV10(new UnityLogger().CastFast()).CastFast()); + Main.RealOptionsData.Restore(new NormalGameOptionsV11(new UnityLogger().CastFast()).CastFast()); protected override bool IsDirty { get; set; } @@ -640,6 +640,9 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS case CustomRoles.DetectiveEHR: AURoleOptions.DetectiveSuspectLimit = CrewmateVanillaRoles.DetectiveSuspectLimit.GetFloat(); break; + case CustomRoles.JudgeEHR: + AURoleOptions.JudgeTaskRequirementPercentage = CrewmateVanillaRoles.JudgeTaskRequirementPercentage.GetFloat(); + break; } // When impostor alert is off, and the player is a desync crewmate, set impostor alert as true diff --git a/Modules/GameState.cs b/Modules/GameState.cs index cfe21a87d..697e0a3d7 100644 --- a/Modules/GameState.cs +++ b/Modules/GameState.cs @@ -379,7 +379,7 @@ public class PlayerState(byte playerId) RPC.SendDeathReason(PlayerId, deathReason, IsDead); Utils.CheckAndSpawnAdditionalRenegade(GameData.Instance.GetPlayerById(PlayerId)); - if (GameStates.IsMeeting && MeetingHud.Instance.state is MeetingHud.VoteStates.Discussion or MeetingHud.VoteStates.NotVoted or MeetingHud.VoteStates.Voted) + if (GameStates.IsMeeting && MeetingHud.Instance.state is MeetingHud.MeetingStates.Discussion or MeetingHud.MeetingStates.NotVoted or MeetingHud.MeetingStates.Voted) MeetingHud.Instance.CheckForEndVoting(); } } @@ -592,7 +592,7 @@ public static class GameStates public static bool IsFreePlay => AmongUsClient.Instance.NetworkMode == NetworkModes.FreePlay; public static bool IsInTask => InGame && !MeetingHud.Instance; public static bool IsMeeting => InGame && MeetingHud.Instance; - public static bool IsVoting => IsMeeting && MeetingHud.Instance.state is MeetingHud.VoteStates.Voted or MeetingHud.VoteStates.NotVoted; + public static bool IsVoting => IsMeeting && MeetingHud.Instance.state is MeetingHud.MeetingStates.Voted or MeetingHud.MeetingStates.NotVoted; public static bool IsCountDown => GameStartManager.InstanceExists && GameStartManager.Instance.startState == GameStartManager.StartingStates.Countdown; diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index 4028c3b8d..726cbaf2f 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -63,9 +63,9 @@ public static class GuessManager public static bool GuesserMsg(PlayerControl pc, string msg, bool isUI = false) { if (!AmongUsClient.Instance.AmHost) return false; - if (!GameStates.IsMeeting || MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding || !pc) return false; + if (!GameStates.IsMeeting || MeetingHud.Instance.state is MeetingHud.MeetingStates.Results or MeetingHud.MeetingStates.Proceeding || !pc) return false; - bool hasGuessingRole = pc.GetCustomRole() is CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Doomsayer or CustomRoles.Judge or CustomRoles.Swapper or CustomRoles.Councillor or CustomRoles.NecroGuesser or CustomRoles.Augur; + bool hasGuessingRole = pc.GetCustomRole() is CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Doomsayer or CustomRoles.JudgeOld or CustomRoles.Swapper or CustomRoles.Councillor or CustomRoles.NecroGuesser or CustomRoles.Augur; if (!hasGuessingRole && !pc.Is(CustomRoles.Guesser) && !Options.GuesserMode.GetBool()) return false; int operate; // 1: ID, 2: Guess @@ -91,7 +91,7 @@ public static class GuessManager return true; } - if (!Options.CanGuessDuringDiscussionTime.GetBool() && MeetingHud.Instance && MeetingHud.Instance.state is MeetingHud.VoteStates.Discussion or MeetingHud.VoteStates.Animating && Main.RealOptionsData.GetInt(Int32OptionNames.DiscussionTime) > 0) + if (!Options.CanGuessDuringDiscussionTime.GetBool() && MeetingHud.Instance && MeetingHud.Instance.state is MeetingHud.MeetingStates.Discussion or MeetingHud.MeetingStates.Animating && Main.RealOptionsData.GetInt(Int32OptionNames.DiscussionTime) > 0) { ShowMessage("GuessDuringDiscussion"); return true; @@ -610,21 +610,21 @@ public static class GuessManager foreach (PlayerVoteArea playerVoteArea in meetingHud.playerStates) { - if (playerVoteArea.VotedFor != pc.PlayerId) continue; + if (playerVoteArea.VotedForId != pc.PlayerId) continue; playerVoteArea.UnsetVote(); meetingHud.SetDirtyBit(1U); - PlayerControl voteAreaPlayer = Utils.GetPlayerById(playerVoteArea.TargetPlayerId); + PlayerControl voteAreaPlayer = Utils.GetPlayerById(playerVoteArea.PlayerId); if (!voteAreaPlayer) continue; if (!voteAreaPlayer.AmOwner) { - meetingHud.RpcClearVote(voteAreaPlayer.OwnerId); + meetingHud.RpcClearVote(playerVoteArea.PlayerId); meetingHud.SetDirtyBit(1U); } else - meetingHud.ClearVote(); + meetingHud.ClearVote(playerVoteArea.PlayerId, true); } MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.GuessKill, SendOption.Reliable); @@ -654,7 +654,7 @@ public static class GuessManager meetingHud.SetForegroundForDead(); } - PlayerVoteArea voteArea = MeetingHud.Instance.playerStates.First(x => x.TargetPlayerId == pc.PlayerId); + PlayerVoteArea voteArea = meetingHud.playerStates.First(x => x.PlayerId == pc.PlayerId); if (voteArea.DidVote) { @@ -663,7 +663,7 @@ public static class GuessManager if (AmongUsClient.Instance.AmHost) { meetingHud.SetDirtyBit(1U); - meetingHud.RpcClearVote(pc.OwnerId); + meetingHud.RpcClearVote(voteArea.PlayerId); meetingHud.SetDirtyBit(1U); } } @@ -684,14 +684,12 @@ public static class GuessManager foreach (PlayerVoteArea playerVoteArea in meetingHud.playerStates) { - if (playerVoteArea.VotedFor != pc.PlayerId) continue; + if (playerVoteArea.VotedForId != pc.PlayerId) continue; playerVoteArea.UnsetVote(); - PlayerControl voteAreaPlayer = Utils.GetPlayerById(playerVoteArea.TargetPlayerId); - if (!voteAreaPlayer.AmOwner) continue; - - meetingHud.ClearVote(); + PlayerControl voteAreaPlayer = Utils.GetPlayerById(playerVoteArea.PlayerId); + meetingHud.ClearVote(playerVoteArea.PlayerId, voteAreaPlayer.AmOwner); } } catch (Exception e) { Utils.ThrowException(e); } @@ -740,13 +738,13 @@ public static class GuessManager { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc) continue; bool skip = PlayerControl.LocalPlayer.Is(CustomRoles.NecroGuesser) switch { - true => pc.IsAlive() || pc.Is(CustomRoles.Gravestone) || (Options.SeeEjectedRolesInMeeting.GetBool() && Main.PlayerStates[pva.TargetPlayerId].deathReason == PlayerState.DeathReason.Vote), + true => pc.IsAlive() || pc.Is(CustomRoles.Gravestone) || (Options.SeeEjectedRolesInMeeting.GetBool() && Main.PlayerStates[pva.PlayerId].deathReason == PlayerState.DeathReason.Vote), false => !pc.IsAlive() }; @@ -761,7 +759,7 @@ public static class GuessManager var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); PlayerVoteArea pva1 = pva; - button.OnClick.AddListener((Action)(() => GuesserOnClick(pva1.TargetPlayerId, __instance))); + button.OnClick.AddListener((Action)(() => GuesserOnClick(pva1.PlayerId, __instance))); } } @@ -799,7 +797,7 @@ public static class GuessManager public static void GuesserOnClick(byte playerId, MeetingHud __instance, bool specificRoleChoosing = false) { PlayerControl pc = Utils.GetPlayerById(playerId); - if (!pc || !pc.IsAlive() || GuesserUI || MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding || Starspawn.IsDayBreak) return; + if (!pc || !pc.IsAlive() || GuesserUI || MeetingHud.Instance.state is MeetingHud.MeetingStates.Results or MeetingHud.MeetingStates.Proceeding || Starspawn.IsDayBreak) return; try { @@ -1032,7 +1030,7 @@ public static class GuessManager } else { - if (MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding || !PlayerControl.LocalPlayer.IsAlive()) return; + if (MeetingHud.Instance.state is MeetingHud.MeetingStates.Results or MeetingHud.MeetingStates.Proceeding || !PlayerControl.LocalPlayer.IsAlive()) return; Logger.Msg($"Click: {pc.GetNameWithRole()} => {role}", "Guesser UI"); diff --git a/Modules/OptionBackup/OptionBackupData.cs b/Modules/OptionBackup/OptionBackupData.cs index a22c795b9..6a7527435 100644 --- a/Modules/OptionBackup/OptionBackupData.cs +++ b/Modules/OptionBackup/OptionBackupData.cs @@ -42,7 +42,7 @@ public class OptionBackupData // Since TryGetUInt is not implemented, get it separately AllValues.Add(new UIntOptionBackupValue(UInt32OptionNames.Keywords, (uint)option.Keywords)); - RoleTypes[] array = [RoleTypes.Scientist, RoleTypes.Engineer, RoleTypes.GuardianAngel, RoleTypes.Shapeshifter, RoleTypes.Noisemaker, RoleTypes.Phantom, RoleTypes.Tracker, RoleTypes.Viper, RoleTypes.Detective]; + RoleTypes[] array = [RoleTypes.Scientist, RoleTypes.Engineer, RoleTypes.GuardianAngel, RoleTypes.Shapeshifter, RoleTypes.Noisemaker, RoleTypes.Phantom, RoleTypes.Tracker, RoleTypes.Viper, RoleTypes.Detective, RoleTypes.Judge]; foreach (RoleTypes role in array) AllValues.Add(new RoleRateBackupValue(role, option.RoleOptions.GetNumPerGame(role), option.RoleOptions.GetChancePerGame(role))); } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 79f44de9d..4189258ce 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -587,7 +587,7 @@ public static class Utils if (Options.CurrentGameMode == CustomGameMode.HideAndSeek && targetMainRole == CustomRoles.Agent && CustomHnS.PlayerRoles[seerId].Interface.Team != Team.Impostor) targetMainRole = CustomRoles.Hider; - if ((ExileController.Instance || targetState.IsDead || (GameStates.IsMeeting && MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding or MeetingHud.VoteStates.Voted or MeetingHud.VoteStates.NotVoted)) && !GameStates.IsEnded && Forger.Forges.TryGetValue(targetId, out var forgedRole)) + if ((ExileController.Instance || targetState.IsDead || (GameStates.IsMeeting && MeetingHud.Instance.state is MeetingHud.MeetingStates.Results or MeetingHud.MeetingStates.Proceeding or MeetingHud.MeetingStates.Voted or MeetingHud.MeetingStates.NotVoted)) && !GameStates.IsEnded && Forger.Forges.TryGetValue(targetId, out var forgedRole)) targetMainRole = forgedRole; if (!self && seerMainRole.IsImpostor() && targetMainRole == CustomRoles.DoubleAgent && DoubleAgent.ShownRoles != null && DoubleAgent.ShownRoles.TryGetValue(targetId, out CustomRoles shownRole)) @@ -1103,7 +1103,7 @@ public static class Utils (pc.Is(CustomRoles.Mayor) && !Options.MayorCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.NiceGuesser) && !Options.NGuesserCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Snitch) && !Options.SnitchCanBeMadmate.GetBool()) || - (pc.Is(CustomRoles.Judge) && !Options.JudgeCanBeMadmate.GetBool()) || + (pc.Is(CustomRoles.JudgeOld) && !Options.JudgeCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Marshall) && !Options.MarshallCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Investigator) && !Options.InvestigatorCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.President) && !Options.PresidentCanBeMadmate.GetBool()) || diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 6ca86a0ab..6e8f56351 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -2389,7 +2389,7 @@ internal static class ChatCommands if (text.Length < 6 || !GameStates.IsMeeting) return; string toVote = text[6..].Replace(" ", string.Empty); - if (!byte.TryParse(toVote, out byte voteId) || MeetingHud.Instance.playerStates?.FirstOrDefault(x => x.TargetPlayerId == player.PlayerId)?.DidVote is true or null) return; + if (!byte.TryParse(toVote, out byte voteId) || MeetingHud.Instance.playerStates?.FirstOrDefault(x => x.PlayerId == player.PlayerId)?.DidVote is true or null) return; if (voteId > PlayerControl.AllPlayerControls.Count) return; @@ -3530,7 +3530,7 @@ internal static class ChatCommands var commandEntered = false; - if (text.StartsWith('/') && !player.IsModdedClient() && (!GameStates.IsMeeting || MeetingHud.Instance.state is not MeetingHud.VoteStates.Results and not MeetingHud.VoteStates.Proceeding)) + if (text.StartsWith('/') && !player.IsModdedClient() && (!GameStates.IsMeeting || MeetingHud.Instance.state is not MeetingHud.MeetingStates.Results and not MeetingHud.MeetingStates.Proceeding)) { Utils.CheckServerCommand(ref text, out bool spamRequired); if (!spamRequired) canceled = true; diff --git a/Patches/CheckGameEndPatch.cs b/Patches/CheckGameEndPatch.cs index de68c073b..04d93fc85 100644 --- a/Patches/CheckGameEndPatch.cs +++ b/Patches/CheckGameEndPatch.cs @@ -1456,6 +1456,7 @@ internal static class GameEndChecker or RoleTypes.Noisemaker or RoleTypes.Tracker or RoleTypes.Detective + or RoleTypes.Judge or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel) { diff --git a/Patches/Crowded.cs b/Patches/Crowded.cs index 87a1d41bb..592d28e99 100644 --- a/Patches/Crowded.cs +++ b/Patches/Crowded.cs @@ -266,11 +266,11 @@ internal static class Crowded } } - [HarmonyPatch(typeof(NormalGameOptionsV10), nameof(NormalGameOptionsV10.AreInvalid))] + [HarmonyPatch(typeof(NormalGameOptionsV11), nameof(NormalGameOptionsV11.AreInvalid))] public static class InvalidOptionsPatches { [SuppressMessage("ReSharper", "UnusedMember.Global")] - public static bool Prefix(NormalGameOptionsV10 __instance, [HarmonyArgument(0)] int maxExpectedPlayers) + public static bool Prefix(NormalGameOptionsV11 __instance, [HarmonyArgument(0)] int maxExpectedPlayers) { return __instance.MaxPlayers > maxExpectedPlayers || __instance.NumImpostors < 1 || @@ -465,7 +465,7 @@ public class MeetingHudPagingBehaviour(IntPtr ptr) : AbstractPagingBehaviour(ptr { base.Update(); // Sometimes the timer text is spammed with the page counter for some eccentric reason, so this is just a Band-Aid fix for it - if (meetingHud.state is MeetingHud.VoteStates.Animating or MeetingHud.VoteStates.Proceeding || meetingHud.TimerText.text.Contains($" ({PageIndex + 1}/{MaxPageIndex + 1})")) return; // TimerText does not update there + if (meetingHud.state is MeetingHud.MeetingStates.Animating or MeetingHud.MeetingStates.Proceeding || meetingHud.TimerText.text.Contains($" ({PageIndex + 1}/{MaxPageIndex + 1})")) return; // TimerText does not update there meetingHud.TimerText.text += $" ({PageIndex + 1}/{MaxPageIndex + 1})"; } diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 698fb4012..7c340bff5 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -428,7 +428,7 @@ internal static class HudManagerPatch ActionButton button; Type type = state.Role.GetType(); - if (type.GetMethod("OnVote").DeclaringType == type || role is CustomRoles.Adrenaline or CustomRoles.Battery or CustomRoles.Dad or CustomRoles.Grappler or CustomRoles.Inquirer or CustomRoles.Judge or CustomRoles.Mechanic or CustomRoles.Medium or CustomRoles.Swapper or CustomRoles.Inspector or CustomRoles.Spy or CustomRoles.Councillor or CustomRoles.CursedWolf or CustomRoles.Forger or CustomRoles.Generator or CustomRoles.Ventriloquist or CustomRoles.Bargainer or CustomRoles.Technician or CustomRoles.Virus) + if (type.GetMethod("OnVote").DeclaringType == type || role is CustomRoles.Adrenaline or CustomRoles.Battery or CustomRoles.Dad or CustomRoles.Grappler or CustomRoles.Inquirer or CustomRoles.JudgeOld or CustomRoles.Mechanic or CustomRoles.Medium or CustomRoles.Swapper or CustomRoles.Inspector or CustomRoles.Spy or CustomRoles.Councillor or CustomRoles.CursedWolf or CustomRoles.Forger or CustomRoles.Generator or CustomRoles.Ventriloquist or CustomRoles.Bargainer or CustomRoles.Technician or CustomRoles.Virus) button = null; else if (role is CustomRoles.Coroner or CustomRoles.Occultist or CustomRoles.Vulture) button = __instance.ReportButton; diff --git a/Patches/HudSpritePatch.cs b/Patches/HudSpritePatch.cs index 744095fc4..90ccd984f 100644 --- a/Patches/HudSpritePatch.cs +++ b/Patches/HudSpritePatch.cs @@ -134,7 +134,7 @@ public static class HudSpritePatch newAbilityButton = CustomButton.Get("Kill"); break; } - case CustomRoles.Judge: + case CustomRoles.JudgeOld: { newAbilityButton = CustomButton.Get("JudgeIcon"); break; diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs index a6b8251b1..0d765dfb1 100644 --- a/Patches/IntroPatch.cs +++ b/Patches/IntroPatch.cs @@ -79,7 +79,7 @@ static class CoShowIntroPatch __instance.IsIntroDisplayed = true; __instance.LobbyTimerExtensionUI.HideAll(); - __instance.SetMapButtonEnabled(false); + __instance.SetMapAndInfoButtonsEnabled(false); __instance.FullScreen.transform.localPosition = new Vector3(0.0f, 0.0f, -250f); yield return __instance.ShowEmblem(true); @@ -96,7 +96,7 @@ static class CoShowIntroPatch yield return __instance.CoFadeFullScreen(Color.black, Color.clear); __instance.FullScreen.transform.localPosition = new Vector3(0.0f, 0.0f, -500f); __instance.IsIntroDisplayed = false; - __instance.SetMapButtonEnabled(true); + __instance.SetMapAndInfoButtonsEnabled(true); __instance.SetHudActive(true); __instance.CrewmatesKilled.gameObject.SetActive(GameManager.Instance.ShowCrewmatesKilled()); GameManager.Instance.StartGame(); @@ -812,6 +812,11 @@ internal static class BeginCrewmatePatch or CustomRoles.Vacuum => GetIntroSound(RoleTypes.Noisemaker), + CustomRoles.Judge + or CustomRoles.JudgeEHR + or CustomRoles.JudgeOld + => GetIntroSound(RoleTypes.Judge), + CustomRoles.Phantom or CustomRoles.PhantomEHR or CustomRoles.Ambusher diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index bebaf3536..9205ce300 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -1,13 +1,14 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; using AmongUs.GameOptions; using EHR.Gamemodes; using EHR.Modules; using EHR.Roles; using HarmonyLib; using Hazel; +using InnerNet; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; using TMPro; using UnityEngine; using static EHR.Translator; @@ -44,12 +45,12 @@ internal static class CheckForEndVotingPatch { if (!pva) continue; - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc) continue; // Dictators who are not dead have already voted. // Take the initiative to rebel - if (pva.DidVote && pc.PlayerId == pva.VotedFor && pva.VotedFor < 253 && pc.IsAlive()) + if (pva.DidVote && pc.PlayerId == pva.VotedForId && pva.VotedForId < 253 && pc.IsAlive()) { if (Options.MadmateSpawnMode.GetInt() == 2 && Main.MadmateNum < CustomRoles.Madmate.GetCount() && pc.CanBeMadmate()) { @@ -60,15 +61,15 @@ internal static class CheckForEndVotingPatch } } - if (pc.Is(CustomRoles.Dictator) && pva.DidVote && pc.PlayerId != pva.VotedFor && pva.VotedFor < 253 && pc.Data?.IsDead == false && pc.GetTaskState().CompletedTasksCount >= Dictator.MinTasksToDictate.GetInt()) + if (pc.Is(CustomRoles.Dictator) && pva.DidVote && pc.PlayerId != pva.VotedForId && pva.VotedForId < 253 && pc.Data?.IsDead == false && pc.GetTaskState().CompletedTasksCount >= Dictator.MinTasksToDictate.GetInt()) { - PlayerControl voteTarget = Utils.GetPlayerById(pva.VotedFor); + PlayerControl voteTarget = Utils.GetPlayerById(pva.VotedForId); TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.Suicide, pc.PlayerId); StatesList.Add(new() { - VoterId = pva.TargetPlayerId, - VotedForId = pva.VotedFor + VoterId = pva.PlayerId, + VotedForId = pva.VotedForId }); States = [.. StatesList]; @@ -80,12 +81,12 @@ internal static class CheckForEndVotingPatch if (Main.LastVotedPlayerInfo != null) ConfirmEjections(Main.LastVotedPlayerInfo, false); - __instance.RpcVotingComplete(States.ToArray(), voteTarget.Data, false); + __instance.RpcVotingComplete(States.ToArray(), voteTarget.Data, false, false, 0); Statistics.OnVotingComplete(States.ToArray(), voteTarget.Data, false, true); Logger.Info($"{voteTarget.GetNameWithRole()} expelled by dictator", "Dictator"); - CheckForDeathOnExile(PlayerState.DeathReason.Vote, pva.VotedFor); + CheckForDeathOnExile(PlayerState.DeathReason.Vote, pva.VotedForId); Logger.Info("Dictatorship vote, forced end of meeting", "Special Phase"); MeetingHudRpcClosePatch.AllowClose = true; @@ -93,16 +94,16 @@ internal static class CheckForEndVotingPatch return true; } - if (pva.DidVote && pva.VotedFor < 253 && pc.IsAlive()) + if (pva.DidVote && pva.VotedForId < 253 && pc.IsAlive()) { - PlayerControl voteTarget = Utils.GetPlayerById(pva.VotedFor); + PlayerControl voteTarget = Utils.GetPlayerById(pva.VotedForId); if (!voteTarget || !voteTarget.IsAlive() || !voteTarget.Data || voteTarget.Data.Disconnected) { pva.UnsetVote(); - __instance.RpcClearVote(pc.OwnerId); - __instance.UpdateButtons(); - pva.VotedFor = byte.MaxValue; + __instance.RpcClearVote(pva.PlayerId); + __instance.UpdateForeground(); + pva.VotedForId = byte.MaxValue; } else if (voteTarget && !pc.GetCustomRole().CancelsVote() && !pc.UsesMeetingShapeshift()) Main.PlayerStates[pc.PlayerId].Role.OnVote(pc, voteTarget); @@ -112,8 +113,8 @@ internal static class CheckForEndVotingPatch if (!ShouldSkip && !__instance.playerStates.All(ps => { - if (!ps || Silencer.ForSilencer.Contains(ps.TargetPlayerId) || !Main.PlayerStates.TryGetValue(ps.TargetPlayerId, out PlayerState st) || st.IsDead || ps.AmDead || ps.DidVote) return true; - PlayerControl targetPlayer = Utils.GetPlayerById(ps.TargetPlayerId); + if (!ps || Silencer.ForSilencer.Contains(ps.PlayerId) || !Main.PlayerStates.TryGetValue(ps.PlayerId, out PlayerState st) || st.IsDead || ps.AmDead || ps.DidVote) return true; + PlayerControl targetPlayer = Utils.GetPlayerById(ps.PlayerId); return !targetPlayer || !targetPlayer.Data || targetPlayer.Data.Disconnected; })) return false; @@ -125,13 +126,13 @@ internal static class CheckForEndVotingPatch { if (!ps) continue; - voteLog.Info($"{ps.TargetPlayerId,-2}{$"({Utils.GetVoteName(ps.TargetPlayerId)})".PadRightV2(40)}:{ps.VotedFor,-3}({Utils.GetVoteName(ps.VotedFor)})"); - PlayerControl voter = Utils.GetPlayerById(ps.TargetPlayerId); + voteLog.Info($"{ps.PlayerId,-2}{$"({Utils.GetVoteName(ps.PlayerId)})".PadRightV2(40)}:{ps.VotedForId,-3}({Utils.GetVoteName(ps.VotedForId)})"); + PlayerControl voter = Utils.GetPlayerById(ps.PlayerId); if (!voter || !voter.Data || voter.Data.Disconnected) continue; if (Options.VoteMode.GetBool()) { - if (ps.VotedFor == 253 && voter.IsAlive() && + if (ps.VotedForId == 253 && voter.IsAlive() && !(Options.WhenSkipVoteIgnoreFirstMeeting.GetBool() && MeetingStates.FirstMeeting) && !(Options.WhenSkipVoteIgnoreNoDeadBody.GetBool() && !MeetingStates.IsExistDeadBody) && !(Options.WhenSkipVoteIgnoreEmergency.GetBool() && MeetingStates.IsEmergencyMeeting) @@ -140,54 +141,54 @@ internal static class CheckForEndVotingPatch switch (Options.GetWhenSkipVote()) { case VoteMode.Suicide: - TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.SkippedVote, ps.TargetPlayerId); + TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.SkippedVote, ps.PlayerId); voteLog.Info($"{voter.GetNameWithRole()} Commit suicide for skipping voting"); break; case VoteMode.SelfVote: - ps.VotedFor = ps.TargetPlayerId; + ps.VotedForId = ps.PlayerId; voteLog.Info($"{voter.GetNameWithRole()} Self-voting due to skipping voting"); break; } } - if (ps.VotedFor == 254 && voter.IsAlive()) + if (ps.VotedForId == 254 && voter.IsAlive()) { switch (Options.GetWhenNonVote()) { case VoteMode.Suicide: - TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.DidntVote, ps.TargetPlayerId); + TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.DidntVote, ps.PlayerId); voteLog.Info($"{voter.GetNameWithRole()} Committed suicide for not voting"); break; case VoteMode.SelfVote: - ps.VotedFor = ps.TargetPlayerId; + ps.VotedForId = ps.PlayerId; voteLog.Info($"{voter.GetNameWithRole()} Self-voting due to not voting"); break; case VoteMode.Skip: - ps.VotedFor = 253; + ps.VotedForId = 253; voteLog.Info($"{voter.GetNameWithRole()} Skip for not voting"); break; } } } - if (ps.VotedFor == 254 && voter.IsAlive() && voter.Is(CustomRoles.Compelled)) - TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.DidntVote, ps.TargetPlayerId); + if (ps.VotedForId == 254 && voter.IsAlive() && voter.Is(CustomRoles.Compelled)) + TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.DidntVote, ps.PlayerId); - if (CheckRole(ps.TargetPlayerId, CustomRoles.FortuneTeller) && FortuneTeller.HideVote.GetBool()) continue; - if (CheckRole(ps.TargetPlayerId, CustomRoles.EvilEraser) && EvilEraser.HideVote.GetBool()) continue; - if (CheckRole(ps.TargetPlayerId, CustomRoles.NiceEraser) && NiceEraser.HideVote.GetBool()) continue; - if (CheckRole(ps.TargetPlayerId, CustomRoles.Scout) && Scout.HideVote.GetBool()) continue; - if (CheckRole(ps.TargetPlayerId, CustomRoles.Oracle) && Oracle.HideVote.GetBool()) continue; - if (ps.TargetPlayerId == ps.VotedFor && Options.MadmateSpawnMode.GetInt() == 2 && CustomRoles.Madmate.IsEnable() && MeetingStates.FirstMeeting) continue; + if (CheckRole(ps.PlayerId, CustomRoles.FortuneTeller) && FortuneTeller.HideVote.GetBool()) continue; + if (CheckRole(ps.PlayerId, CustomRoles.EvilEraser) && EvilEraser.HideVote.GetBool()) continue; + if (CheckRole(ps.PlayerId, CustomRoles.NiceEraser) && NiceEraser.HideVote.GetBool()) continue; + if (CheckRole(ps.PlayerId, CustomRoles.Scout) && Scout.HideVote.GetBool()) continue; + if (CheckRole(ps.PlayerId, CustomRoles.Oracle) && Oracle.HideVote.GetBool()) continue; + if (ps.PlayerId == ps.VotedForId && Options.MadmateSpawnMode.GetInt() == 2 && CustomRoles.Madmate.IsEnable() && MeetingStates.FirstMeeting) continue; - bool canVote = !(CheckRole(ps.TargetPlayerId, CustomRoles.Glitch) && !Glitch.CanVote.GetBool()); - if (CheckRole(ps.TargetPlayerId, CustomRoles.Shifter) && !Shifter.CanVote.GetBool()) canVote = false; - if (ps.VotedFor.GetPlayer() && CheckRole(ps.VotedFor, CustomRoles.Zombie)) canVote = false; - if (CheckRole(ps.TargetPlayerId, CustomRoles.Degraded)) canVote = false; - if (Poache.PoachedPlayers != null && Poache.PoachedPlayers.Contains(ps.TargetPlayerId)) canVote = false; - if (Silencer.ForSilencer.Contains(ps.TargetPlayerId) && Main.AllAlivePlayerControlsCount > Silencer.MaxPlayersAliveForSilencedToVote.GetInt()) canVote = false; + bool canVote = !(CheckRole(ps.PlayerId, CustomRoles.Glitch) && !Glitch.CanVote.GetBool()); + if (CheckRole(ps.PlayerId, CustomRoles.Shifter) && !Shifter.CanVote.GetBool()) canVote = false; + if (ps.VotedForId.Value.GetPlayer() && CheckRole(ps.VotedForId, CustomRoles.Zombie)) canVote = false; + if (CheckRole(ps.PlayerId, CustomRoles.Degraded)) canVote = false; + if (Poache.PoachedPlayers != null && Poache.PoachedPlayers.Contains(ps.PlayerId)) canVote = false; + if (Silencer.ForSilencer.Contains(ps.PlayerId) && Main.AllAlivePlayerControlsCount > Silencer.MaxPlayersAliveForSilencedToVote.GetInt()) canVote = false; - switch (Main.PlayerStates[ps.TargetPlayerId].Role) + switch (Main.PlayerStates[ps.PlayerId].Role) { case Adventurer { IsEnable: true } av when av.ActiveWeapons.Contains(Adventurer.Weapon.Proxy): AddVote(); @@ -208,25 +209,25 @@ internal static class CheckForEndVotingPatch if (canVote) AddVote(); - if (CheckRole(ps.TargetPlayerId, CustomRoles.Magistrate) && Magistrate.CallCourtNextMeeting) Loop.Times(Magistrate.ExtraVotes.GetInt(), _ => AddVote()); - if (CheckRole(ps.TargetPlayerId, CustomRoles.Vindicator) && !Options.VindicatorHideVote.GetBool()) Loop.Times(Options.VindicatorAdditionalVote.GetInt(), _ => AddVote()); - if (CheckRole(ps.TargetPlayerId, CustomRoles.Knighted)) AddVote(); + if (CheckRole(ps.PlayerId, CustomRoles.Magistrate) && Magistrate.CallCourtNextMeeting) Loop.Times(Magistrate.ExtraVotes.GetInt(), _ => AddVote()); + if (CheckRole(ps.PlayerId, CustomRoles.Vindicator) && !Options.VindicatorHideVote.GetBool()) Loop.Times(Options.VindicatorAdditionalVote.GetInt(), _ => AddVote()); + if (CheckRole(ps.PlayerId, CustomRoles.Knighted)) AddVote(); - if (CheckRole(ps.TargetPlayerId, CustomRoles.Schizophrenic) && Options.DualVotes.GetBool()) + if (CheckRole(ps.PlayerId, CustomRoles.Schizophrenic) && Options.DualVotes.GetBool()) { - int count = StatesList.Count(x => x.VoterId == ps.TargetPlayerId && x.VotedForId == ps.VotedFor); + int count = StatesList.Count(x => x.VoterId == ps.PlayerId && x.VotedForId == ps.VotedForId); Loop.Times(count, _ => AddVote()); } - if (CheckRole(ps.TargetPlayerId, CustomRoles.Stealer)) + if (CheckRole(ps.PlayerId, CustomRoles.Stealer)) { - var count = (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.TargetPlayerId) * Options.VotesPerKill.GetFloat()); + var count = (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.PlayerId) * Options.VotesPerKill.GetFloat()); Loop.Times(count, _ => AddVote()); } - if (CheckRole(ps.TargetPlayerId, CustomRoles.Pickpocket)) + if (CheckRole(ps.PlayerId, CustomRoles.Pickpocket)) { - var count = (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.TargetPlayerId) * Pickpocket.VotesPerKill.GetFloat()); + var count = (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.PlayerId) * Pickpocket.VotesPerKill.GetFloat()); Loop.Times(count, _ => AddVote()); } @@ -235,8 +236,8 @@ internal static class CheckForEndVotingPatch void AddVote() => StatesList.Add(new() { - VoterId = ps.TargetPlayerId, - VotedForId = ps.VotedFor + VoterId = ps.PlayerId, + VotedForId = ps.VotedForId }); } @@ -343,7 +344,24 @@ internal static class CheckForEndVotingPatch if (Main.LastVotedPlayerInfo != null) ConfirmEjections(Main.LastVotedPlayerInfo, braked); - __instance.RpcVotingComplete(States.ToArray(), exiledPlayer, tie); + // Vanilla Judge code + bool wasOverruled = false; + ushort overruleNonce = 0; + if (__instance.TryGetWinningOverrule(out JudgeOverrule winningOverrule, out NetworkedPlayerInfo judgePlayerInfo, out NetworkedPlayerInfo overruledPlayerInfo)) + { + wasOverruled = true; + overruleNonce = winningOverrule.OverruleNonce; + if (overruledPlayerInfo.Role.TeamType == RoleTeamTypes.Impostor) // Only vanilla impostor, need change code for EHR Impostors + { + exiledPlayer = GameData.Instance.GetPlayerById(winningOverrule.OverruledPlayerId); + } + else + { + exiledPlayer = judgePlayerInfo; + } + } + + __instance.RpcVotingComplete(States.ToArray(), exiledPlayer, tie, wasOverruled, overruleNonce); Statistics.OnVotingComplete(States.ToArray(), exiledPlayer, tie, false); @@ -626,18 +644,18 @@ internal static class ExtendedMeetingHud { if (!ps) continue; - if (ps.VotedFor is not 252 and not byte.MaxValue and not 254) + if (ps.VotedForId.Value is not 252 and not byte.MaxValue and not 254) { var voteNum = 1; - PlayerControl target = Utils.GetPlayerById(ps.VotedFor); + PlayerControl target = Utils.GetPlayerById(ps.VotedForId); if (target) { if (target.Is(CustomRoles.Zombie) || (target.Is(CustomRoles.Shifter) && !Shifter.CanBeVoted.GetBool())) voteNum = 0; - if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.Tiebreaker)) + if (CheckForEndVotingPatch.CheckRole(ps.PlayerId, CustomRoles.Tiebreaker)) { if (!Main.TiebreakerVoteFor.Contains(target.PlayerId)) Main.TiebreakerVoteFor.Add(target.PlayerId); @@ -646,15 +664,15 @@ internal static class ExtendedMeetingHud Collector.CollectorVotes(target, ps); } - if (Poache.PoachedPlayers != null && Poache.PoachedPlayers.Contains(ps.TargetPlayerId)) voteNum = 0; - if (Silencer.ForSilencer.Contains(ps.TargetPlayerId) && Main.AllAlivePlayerControlsCount > Silencer.MaxPlayersAliveForSilencedToVote.GetInt()) voteNum = 0; + if (Poache.PoachedPlayers != null && Poache.PoachedPlayers.Contains(ps.PlayerId)) voteNum = 0; + if (Silencer.ForSilencer.Contains(ps.PlayerId) && Main.AllAlivePlayerControlsCount > Silencer.MaxPlayersAliveForSilencedToVote.GetInt()) voteNum = 0; - if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.Knighted)) voteNum += 1; - if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.Degraded)) voteNum -= 1; - if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.Schizophrenic) && Options.DualVotes.GetBool()) voteNum += voteNum; - if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.Stealer)) voteNum += (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.TargetPlayerId) * Options.VotesPerKill.GetFloat()); + if (CheckForEndVotingPatch.CheckRole(ps.PlayerId, CustomRoles.Knighted)) voteNum += 1; + if (CheckForEndVotingPatch.CheckRole(ps.PlayerId, CustomRoles.Degraded)) voteNum -= 1; + if (CheckForEndVotingPatch.CheckRole(ps.PlayerId, CustomRoles.Schizophrenic) && Options.DualVotes.GetBool()) voteNum += voteNum; + if (CheckForEndVotingPatch.CheckRole(ps.PlayerId, CustomRoles.Stealer)) voteNum += (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.PlayerId) * Options.VotesPerKill.GetFloat()); - switch (Main.PlayerStates[ps.TargetPlayerId].Role) + switch (Main.PlayerStates[ps.PlayerId].Role) { case Dad { IsEnable: true } dad when dad.UsingAbilities.Contains(Dad.Ability.GoForMilk): case Shifter when !Shifter.CanVote.GetBool(): @@ -674,7 +692,7 @@ internal static class ExtendedMeetingHud voteNum += Survivor.AdditionalVote.GetInt(); break; case Pickpocket: - voteNum += (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.TargetPlayerId) * Pickpocket.VotesPerKill.GetFloat()); + voteNum += (int)(Main.EnumeratePlayerControls().Count(x => x.GetRealKiller()?.PlayerId == ps.PlayerId) * Pickpocket.VotesPerKill.GetFloat()); break; case Vindicator: voteNum += Options.VindicatorAdditionalVote.GetInt(); @@ -684,9 +702,9 @@ internal static class ExtendedMeetingHud break; } - if (ps.TargetPlayerId == ps.VotedFor && Options.MadmateSpawnMode.GetInt() == 2 && CustomRoles.Madmate.IsEnable() && MeetingStates.FirstMeeting) voteNum = 0; + if (ps.PlayerId == ps.VotedForId && Options.MadmateSpawnMode.GetInt() == 2 && CustomRoles.Madmate.IsEnable() && MeetingStates.FirstMeeting) voteNum = 0; - dic[ps.VotedFor] = !dic.TryGetValue(ps.VotedFor, out int num) ? voteNum : num + voteNum; + dic[ps.VotedForId] = !dic.TryGetValue(ps.VotedForId, out int num) ? voteNum : num + voteNum; } } @@ -899,7 +917,7 @@ internal static class MeetingHudStartPatch foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl target = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl target = Utils.GetPlayerById(pva.PlayerId); if (!target) continue; bool shouldSeeTargetAddons = seer.PlayerId == target.PlayerId || new[] { seer, target }.All(x => x.Is(Team.Impostor)); @@ -987,7 +1005,7 @@ internal static class MeetingHudStartPatch Transform child = deathReasonTextMeeting.transform.FindChild("RoleTextMeeting"); if (child) Object.Destroy(child.gameObject); - byte id = pva.TargetPlayerId; + byte id = pva.PlayerId; if (Doppelganger.SwappedIDs.FindFirst(x => x.Item1 == id || x.Item2 == id, out var pair)) { @@ -1057,7 +1075,7 @@ internal static class MeetingHudStartPatch { LateTask.New(() => { - if (!MeetingHud.Instance || MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding) return; + if (!MeetingHud.Instance || MeetingHud.Instance.state is MeetingHud.MeetingStates.Results or MeetingHud.MeetingStates.Proceeding) return; var aapc = Main.AllAlivePlayerControlsToList; bool restrictions = Options.GuesserNumRestrictions.GetBool(); @@ -1081,7 +1099,7 @@ internal static class MeetingHudStartPatch { if (!pva) continue; - PlayerControl target = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl target = Utils.GetPlayerById(pva.PlayerId); if (!target) continue; if (seer.GetCustomRole().GetDYRole() is RoleTypes.Shapeshifter or RoleTypes.Phantom) @@ -1224,13 +1242,13 @@ internal static class MeetingHudUpdatePatch private static void ClearShootButton(MeetingHud __instance, bool forceAll = false) { __instance.playerStates.DoIf( - x => (forceAll || !Main.PlayerStates.TryGetValue(x.TargetPlayerId, out PlayerState ps) || ps.IsDead) && x.transform.FindChild("ShootButton"), + x => (forceAll || !Main.PlayerStates.TryGetValue(x.PlayerId, out PlayerState ps) || ps.IsDead) && x.transform.FindChild("ShootButton"), x => Object.Destroy(x.transform.FindChild("ShootButton").gameObject)); } public static bool Prefix(MeetingHud __instance) { - if (__instance.CurrentState != MeetingHud.VoteStates.Results) return true; + if (__instance.CurrentState != MeetingHud.MeetingStates.Results) return true; __instance.discussionTimer += Time.deltaTime; @@ -1241,7 +1259,7 @@ internal static class MeetingHudUpdatePatch if (AmongUsClient.Instance.AmHost && num5 <= 0f) { MeetingHudRpcClosePatch.AllowClose = true; - __instance.state = MeetingHud.VoteStates.Proceeding; + __instance.state = MeetingHud.MeetingStates.Proceeding; __instance.RpcClose(); } @@ -1259,7 +1277,7 @@ internal static class MeetingHudUpdatePatch { __instance.playerStates.DoIf(x => x.HighlightedFX.enabled, x => { - PlayerControl player = Utils.GetPlayerById(x.TargetPlayerId); + PlayerControl player = Utils.GetPlayerById(x.PlayerId); if (player && player.IsAlive()) { @@ -1289,11 +1307,11 @@ internal static class MeetingHudUpdatePatch BufferTime = 10; CustomRoles myRole = PlayerControl.LocalPlayer.GetCustomRole(); - //__instance.playerStates.Where(x => (!Main.PlayerStates.TryGetValue(x.TargetPlayerId, out PlayerState ps) || ps.IsDead) && !x.AmDead).Do(x => x.SetDead(x.DidReport, true)); + //__instance.playerStates.Where(x => (!Main.PlayerStates.TryGetValue(x.PlayerId, out PlayerState ps) || ps.IsDead) && !x.AmDead).Do(x => x.SetDead(x.DidReport, true)); switch (myRole) { - case CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Judge or CustomRoles.Swapper or CustomRoles.Councillor or CustomRoles.Guesser when !PlayerControl.LocalPlayer.IsAlive(): + case CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.JudgeOld or CustomRoles.Swapper or CustomRoles.Councillor or CustomRoles.Guesser when !PlayerControl.LocalPlayer.IsAlive(): ClearShootButton(__instance, true); break; case CustomRoles.Nemesis when !PlayerControl.LocalPlayer.IsAlive() && !GameObject.Find("ShootButton"): @@ -1408,7 +1426,7 @@ internal static class MeetingHudCastVotePatch { public static readonly Dictionary ShouldCancelVoteList = []; - public static bool Prefix(MeetingHud __instance, [HarmonyArgument(0)] byte srcPlayerId, [HarmonyArgument(1)] byte suspectPlayerId) + public static bool Prefix(MeetingHud __instance, [HarmonyArgument(0)] PlayerId srcPlayerId, [HarmonyArgument(1)] PlayerId suspectPlayerId) { if (!AmongUsClient.Instance.AmHost) return true; @@ -1418,8 +1436,8 @@ internal static class MeetingHudCastVotePatch foreach (PlayerVoteArea t in __instance.playerStates) { - if (t.TargetPlayerId == srcPlayerId) pvaSrc = t; - if (t.TargetPlayerId == suspectPlayerId) pvaTarget = t; + if (t.PlayerId == srcPlayerId) pvaSrc = t; + if (t.PlayerId == suspectPlayerId) pvaTarget = t; } if (!pvaSrc) @@ -1474,7 +1492,7 @@ internal static class MeetingHudCastVotePatch return skip || !voteCanceled; // skips and invalid votes are never canceled } - public static void Postfix([HarmonyArgument(0)] byte srcPlayerId) + public static void Postfix([HarmonyArgument(0)] PlayerId srcPlayerId) { if (!ShouldCancelVoteList.TryGetValue(srcPlayerId, out (MeetingHud MeetingHud, PlayerVoteArea SourcePVA, PlayerControl SourcePC) info)) return; @@ -1485,10 +1503,10 @@ internal static class MeetingHudCastVotePatch } catch { } - info.MeetingHud.RpcClearVote(info.SourcePC.OwnerId); + info.MeetingHud.RpcClearVote(info.SourcePVA.PlayerId); info.MeetingHud.SetDirtyBit(1U); - info.SourcePVA.VotedFor = byte.MaxValue; + info.SourcePVA.VotedForId = byte.MaxValue; ShouldCancelVoteList.Remove(srcPlayerId); diff --git a/Patches/OnGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs index e8407efbd..21a1964a5 100644 --- a/Patches/OnGameStartedPatch.cs +++ b/Patches/OnGameStartedPatch.cs @@ -54,7 +54,8 @@ internal static class ChangeRoleSettings RoleTypes.Phantom, RoleTypes.Tracker, RoleTypes.Detective, - RoleTypes.Viper + RoleTypes.Viper, + RoleTypes.Judge }.Do(x => Main.NormalOptions.roleOptions.SetRoleRate(x, 0, 0)); if (Main.NormalOptions.MapId > 5 && !(Main.NormalOptions.MapId == 6 && SubmergedCompatibility.Loaded) && !Main.LIMap) @@ -381,7 +382,7 @@ internal static class StartGameHostPatch public static readonly Dictionary> BasisChangingAddons = []; - private static RoleOptionsCollectionV10 RoleOpt => Main.NormalOptions.roleOptions; + private static RoleOptionsCollectionV11 RoleOpt => Main.NormalOptions.roleOptions; private static System.Collections.IEnumerator WaitAndSmoothlyUpdate(this LoadingBarManager loadingBarManager, float startPercent, float targetPercent, float duration, string loadingText) { @@ -1188,7 +1189,7 @@ internal static class StartGameHostPatch if (Options.CurrentGameMode == CustomGameMode.Standard) { - if (target.Is(Team.Crewmate) && roleType is not (RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Engineer or RoleTypes.Noisemaker or RoleTypes.Tracker or RoleTypes.Detective or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel)) + if (target.Is(Team.Crewmate) && roleType is not (RoleTypes.Crewmate or RoleTypes.Scientist or RoleTypes.Engineer or RoleTypes.Noisemaker or RoleTypes.Tracker or RoleTypes.Detective or RoleTypes.Judge or RoleTypes.CrewmateGhost or RoleTypes.GuardianAngel)) displayRole = RoleTypes.Crewmate; if (target.Is(Team.Impostor) && roleType is not (RoleTypes.Impostor or RoleTypes.Shapeshifter or RoleTypes.Phantom or RoleTypes.Viper or RoleTypes.ImpostorGhost)) diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index b4c18efb1..46fac884b 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -847,7 +847,7 @@ internal static class ShapeshiftPatch { public static bool ProcessShapeshift(PlayerControl shapeshifter, PlayerControl target) { - if (MeetingHud.Instance && MeetingHud.Instance.state == MeetingHud.VoteStates.Results) return true; + if (MeetingHud.Instance && MeetingHud.Instance.state == MeetingHud.MeetingStates.Results) return true; bool meetingSS = Options.UseMeetingShapeshift.GetBool() && GameStates.IsMeeting; if ((!Main.ProcessShapeshifts && !meetingSS) || shapeshifter.PlayerId >= 254) return true; @@ -864,7 +864,7 @@ internal static class ShapeshiftPatch if (AmongUsClient.Instance.AmHost && meetingSS) { - if (MeetingHud.Instance.state is MeetingHud.VoteStates.Discussion or MeetingHud.VoteStates.Voted or MeetingHud.VoteStates.NotVoted) + if (MeetingHud.Instance.state is MeetingHud.MeetingStates.Discussion or MeetingHud.MeetingStates.Voted or MeetingHud.MeetingStates.NotVoted) Main.PlayerStates[shapeshifter.PlayerId].Role.OnMeetingShapeshift(shapeshifter, target); shapeshifter.RpcRejectShapeshift(); @@ -2425,7 +2425,7 @@ internal static class GameDataCompleteTaskPatch { try { - if (MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) return; + if (MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.MeetingStates.Animating) return; if (Options.CurrentGameMode == CustomGameMode.HideAndSeek && CustomHnS.PlayerRoles[pc.PlayerId].Interface.Team == Team.Crewmate && pc.IsAlive()) { @@ -2623,6 +2623,7 @@ internal static class PlayerControlLocalSetRolePatch RoleTypes.Tracker => CustomRoles.TrackerEHR, RoleTypes.Detective => CustomRoles.DetectiveEHR, RoleTypes.Viper => CustomRoles.ViperEHR, + RoleTypes.Judge => CustomRoles.JudgeEHR, _ => CustomRoles.NotAssigned }; diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index 078d0e0e7..d1d791c75 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -630,6 +630,10 @@ "DetectiveEHRInfoLong": "(Crewmates):\\nAs the Detective, you can write down notes about each crime scene and interrogate suspects.\n\nThis role currently does not work due to a basis reset issue.", "AbilityButtonText.Detective": "Notes", "SecondaryAbilityButtonText.Detective": "Interrogate", + "JudgeEHR": "Judge", + "JudgeEHRInfo": "Silence in the courtroom!", + "JudgeEHRInfoLong": "(Crewmates):\\nOverrule a meeting to eject an Impostor.\\nIf wrong, you get ejected.", + "JudgeTaskRequirementPercentage": "Task Unlock", "Detour": "Detour", "DetourInfo": "Pass Kills Onto Nearest Player", "DetourInfoLong": "(Crewmate):\\nAs the Detour, all kill button related actions on you will be blocked and instead happen on the closest player to you.", @@ -989,9 +993,9 @@ "JournalistError.IndexOutOfRange": "You didn't provide enough arguments.", "JournalistError.InvalidArgument": "Invalid argument. Use /cmd note {add/remove/clear/view} [value]", "JournalistError.Unknown": "An unknown error occurred.", - "Judge": "Judge", - "JudgeInfo": "Silence in the courtroom!", - "JudgeInfoLong": "(Crewmates):\\nThe Judge can judge a player during the meeting. If the target is evil, it's killed; if it's wrong, the Judge dies. Use the /cmd tl [player id] command to judge and /cmd id to view player IDs. Judges can judge all players when they're Madmate.", + "JudgeOld": "Judge", + "JudgeOldInfo": "Silence in the courtroom!", + "JudgeOldInfoLong": "(Crewmates):\\nThe Judge can judge a player during the meeting. If the target is evil, it's killed; if it's wrong, the Judge dies. Use the /cmd tl [player id] command to judge and /cmd id to view player IDs. Judges can judge all players when they're Madmate.", "JudgeCanBeMadmate": "Judge can become Madmate", "JudgeCanTrialContagious": "Can trial Contagious", "JudgeCanTrialConverted": "Can trial <#ffab1b>Converted players", diff --git a/Roles/Standard/Coven/Summoner.cs b/Roles/Standard/Coven/Summoner.cs index 8ec73fa9a..852e3b393 100644 --- a/Roles/Standard/Coven/Summoner.cs +++ b/Roles/Standard/Coven/Summoner.cs @@ -282,7 +282,7 @@ public class Summoner : CovenBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -293,7 +293,7 @@ public class Summoner : CovenBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Summon.png", 130f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => SummonerOnClick(pva.TargetPlayerId))); + button.OnClick.AddListener((Action)(() => SummonerOnClick(pva.PlayerId))); } } diff --git a/Roles/Standard/Crewmate/Investigate/Analyst.cs b/Roles/Standard/Crewmate/Investigate/Analyst.cs index 835d3a085..9b435cde0 100644 --- a/Roles/Standard/Crewmate/Investigate/Analyst.cs +++ b/Roles/Standard/Crewmate/Investigate/Analyst.cs @@ -83,6 +83,7 @@ internal class Analyst : RoleBase CustomRoles.Noisemaker or CustomRoles.NoisemakerEHR => CustomRoles.Bubble.ColoredTextByRole(GetString("Noisemaker")), CustomRoles.Tracker or CustomRoles.TrackerEHR => CustomRoles.Scout.ColoredTextByRole(GetString("Tracker")), CustomRoles.Detective or CustomRoles.DetectiveEHR => CustomRoles.Forensic.ColoredTextByRole(GetString("Detective")), + CustomRoles.Judge or CustomRoles.JudgeEHR => CustomRoles.JudgeOld.ColoredTextByRole(GetString("Judge")), _ => string.Empty } : string.Empty; diff --git a/Roles/Standard/Crewmate/Investigate/Imitator.cs b/Roles/Standard/Crewmate/Investigate/Imitator.cs index 870bfc792..b66a733b7 100644 --- a/Roles/Standard/Crewmate/Investigate/Imitator.cs +++ b/Roles/Standard/Crewmate/Investigate/Imitator.cs @@ -83,7 +83,7 @@ public class Imitator : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -94,7 +94,7 @@ public class Imitator : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Imitate.png", 130f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => ImitatorOnClick(pva.TargetPlayerId))); + button.OnClick.AddListener((Action)(() => ImitatorOnClick(pva.PlayerId))); } } diff --git a/Roles/Standard/Crewmate/Investigate/Inquirer.cs b/Roles/Standard/Crewmate/Investigate/Inquirer.cs index 1fb27816e..012feb990 100644 --- a/Roles/Standard/Crewmate/Investigate/Inquirer.cs +++ b/Roles/Standard/Crewmate/Investigate/Inquirer.cs @@ -46,7 +46,7 @@ public class Inquirer : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -57,7 +57,7 @@ public class Inquirer : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.InspectorIcon.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.TargetPlayerId, __instance, true))); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.PlayerId, __instance, true))); } } diff --git a/Roles/Standard/Crewmate/Investigate/Inspector.cs b/Roles/Standard/Crewmate/Investigate/Inspector.cs index 353e928a5..2b0797644 100644 --- a/Roles/Standard/Crewmate/Investigate/Inspector.cs +++ b/Roles/Standard/Crewmate/Investigate/Inspector.cs @@ -418,7 +418,7 @@ public class Inspector : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -429,7 +429,7 @@ public class Inspector : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.InspectorIcon.png", 170f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => InspectorOnClick(pva.TargetPlayerId /*, __instance*/))); + button.OnClick.AddListener((Action)(() => InspectorOnClick(pva.PlayerId /*, __instance*/))); } } diff --git a/Roles/Standard/Crewmate/Investigate/Markseeker.cs b/Roles/Standard/Crewmate/Investigate/Markseeker.cs index d15bfbda6..86c04262f 100644 --- a/Roles/Standard/Crewmate/Investigate/Markseeker.cs +++ b/Roles/Standard/Crewmate/Investigate/Markseeker.cs @@ -89,7 +89,7 @@ internal class Markseeker : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -100,7 +100,7 @@ internal class Markseeker : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.prophecies.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => MarkseekerOnClick(pva.TargetPlayerId))); + button.OnClick.AddListener((Action)(() => MarkseekerOnClick(pva.PlayerId))); } } diff --git a/Roles/Standard/Crewmate/Investigate/MeetingManager.cs b/Roles/Standard/Crewmate/Investigate/MeetingManager.cs index cfac638b2..ae7547ecb 100644 --- a/Roles/Standard/Crewmate/Investigate/MeetingManager.cs +++ b/Roles/Standard/Crewmate/Investigate/MeetingManager.cs @@ -48,7 +48,7 @@ public class MeetingManager : RoleBase { if (PlayerIdList == null) return; foreach (byte id in PlayerIdList) - LateTask.New(() => Utils.SendMessage(dp == pc ? string.Format(GetString("MeetingManagerMessageAboutJudgeSuicide"), dp.GetRealName().Replace("\n", " + "), CustomRoles.Judge.ToColoredString()) : string.Format(GetString("MeetingManagerMessageAboutGuessedRole"), dp.GetAllRoleName().Replace("\n", " + ")), id, CustomRoles.MeetingManager.ColoredTextByRole(GetString("MeetingManagerMessageTitle")), importance: MessageImportance.High), 1f, "Meeting Manager Messages"); + LateTask.New(() => Utils.SendMessage(dp == pc ? string.Format(GetString("MeetingManagerMessageAboutJudgeSuicide"), dp.GetRealName().Replace("\n", " + "), CustomRoles.JudgeOld.ToColoredString()) : string.Format(GetString("MeetingManagerMessageAboutGuessedRole"), dp.GetAllRoleName().Replace("\n", " + ")), id, CustomRoles.MeetingManager.ColoredTextByRole(GetString("MeetingManagerMessageTitle")), importance: MessageImportance.High), 1f, "Meeting Manager Messages"); } public static void OnSwap(PlayerControl tg1, PlayerControl tg2) diff --git a/Roles/Standard/Crewmate/Killing/Judge.cs b/Roles/Standard/Crewmate/Killing/Judge.cs index ef44ad087..c0efa04bf 100644 --- a/Roles/Standard/Crewmate/Killing/Judge.cs +++ b/Roles/Standard/Crewmate/Killing/Judge.cs @@ -34,19 +34,19 @@ public class Judge : RoleBase public override void SetupCustomOption() { - Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Judge); - TrialLimitPerMeeting = new FloatOptionItem(Id + 10, "TrialLimitPerMeeting", new(0f, 15f, 1f), 1f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]).SetValueFormat(OptionFormat.Times); - TrialLimitPerGame = new FloatOptionItem(Id + 9, "TrialLimitPerGame", new(0f, 30f, 1f), 3f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]).SetValueFormat(OptionFormat.Times); - AbilityUseLimit = new FloatOptionItem(Id + 18, "AbilityUseLimit", new(0f, 30f, 0.5f), 1f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]).SetValueFormat(OptionFormat.Times); - CanTrialMadmate = new BooleanOptionItem(Id + 12, "JudgeCanTrialMadmate", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialConverted = new BooleanOptionItem(Id + 16, "JudgeCanTrialConverted", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialCrewKilling = new BooleanOptionItem(Id + 13, "JudgeCanTrialnCrewKilling", false, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialNeutralB = new BooleanOptionItem(Id + 14, "JudgeCanTrialNeutralB", false, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialNeutralE = new BooleanOptionItem(Id + 17, "JudgeCanTrialNeutralE", false, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialNeutralK = new BooleanOptionItem(Id + 15, "JudgeCanTrialNeutralK", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialCoven = new BooleanOptionItem(Id + 21, "JudgeCanTrialCoven", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - JudgeAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 19, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 0.3f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]).SetValueFormat(OptionFormat.Times); - AbilityChargesWhenFinishedTasks = new FloatOptionItem(Id + 20, "AbilityChargesWhenFinishedTasks", new(0f, 5f, 0.05f), 0.2f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]).SetValueFormat(OptionFormat.Times); + Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.JudgeOld); + TrialLimitPerMeeting = new FloatOptionItem(Id + 10, "TrialLimitPerMeeting", new(0f, 15f, 1f), 1f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]).SetValueFormat(OptionFormat.Times); + TrialLimitPerGame = new FloatOptionItem(Id + 9, "TrialLimitPerGame", new(0f, 30f, 1f), 3f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]).SetValueFormat(OptionFormat.Times); + AbilityUseLimit = new FloatOptionItem(Id + 18, "AbilityUseLimit", new(0f, 30f, 0.5f), 1f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]).SetValueFormat(OptionFormat.Times); + CanTrialMadmate = new BooleanOptionItem(Id + 12, "JudgeCanTrialMadmate", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]); + CanTrialConverted = new BooleanOptionItem(Id + 16, "JudgeCanTrialConverted", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]); + CanTrialCrewKilling = new BooleanOptionItem(Id + 13, "JudgeCanTrialnCrewKilling", false, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]); + CanTrialNeutralB = new BooleanOptionItem(Id + 14, "JudgeCanTrialNeutralB", false, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]); + CanTrialNeutralE = new BooleanOptionItem(Id + 17, "JudgeCanTrialNeutralE", false, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]); + CanTrialNeutralK = new BooleanOptionItem(Id + 15, "JudgeCanTrialNeutralK", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]); + CanTrialCoven = new BooleanOptionItem(Id + 21, "JudgeCanTrialCoven", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]); + JudgeAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 19, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 0.3f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]).SetValueFormat(OptionFormat.Times); + AbilityChargesWhenFinishedTasks = new FloatOptionItem(Id + 20, "AbilityChargesWhenFinishedTasks", new(0f, 5f, 0.05f), 0.2f, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.JudgeOld]).SetValueFormat(OptionFormat.Times); } public override void Init() @@ -77,7 +77,7 @@ public class Judge : RoleBase public static bool TrialMsg(PlayerControl pc, string msg, bool isUI = false) { - if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || !pc || !pc.Is(CustomRoles.Judge)) return false; + if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || !pc || !pc.Is(CustomRoles.JudgeOld)) return false; int operate; // 1:ID 2:Trial msg = msg.ToLower().TrimStart().TrimEnd(); @@ -187,7 +187,7 @@ public class Judge : RoleBase MeetingManager.OnTrial(dp, pc); Utils.AfterPlayerDeathTasks(dp, true); - LateTask.New(() => Utils.SendMessage(string.Format(GetString("TrialKill"), name), 255, CustomRoles.Judge.ColoredTextByRole(GetString("TrialKillTitle")), importance: MessageImportance.High), 0.6f, "Guess Msg"); + LateTask.New(() => Utils.SendMessage(string.Format(GetString("TrialKill"), name), 255, CustomRoles.JudgeOld.ColoredTextByRole(GetString("TrialKillTitle")), importance: MessageImportance.High), 0.6f, "Guess Msg"); }, 0.2f, "Trial Kill"); } @@ -263,7 +263,7 @@ public class Judge : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -274,7 +274,7 @@ public class Judge : RoleBase renderer.sprite = CustomButton.Get("JudgeIcon"); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => JudgeOnClick(pva.TargetPlayerId /*, __instance*/))); + button.OnClick.AddListener((Action)(() => JudgeOnClick(pva.PlayerId /*, __instance*/))); } } @@ -283,7 +283,7 @@ public class Judge : RoleBase { public static void Postfix(MeetingHud __instance) { - if (PlayerControl.LocalPlayer.Is(CustomRoles.Judge) && PlayerControl.LocalPlayer.IsAlive()) + if (PlayerControl.LocalPlayer.Is(CustomRoles.JudgeOld) && PlayerControl.LocalPlayer.IsAlive()) CreateJudgeButton(__instance); } } diff --git a/Roles/Standard/Crewmate/Killing/Retributionist.cs b/Roles/Standard/Crewmate/Killing/Retributionist.cs index 64029db24..8a97b0b65 100644 --- a/Roles/Standard/Crewmate/Killing/Retributionist.cs +++ b/Roles/Standard/Crewmate/Killing/Retributionist.cs @@ -133,7 +133,7 @@ public class Retributionist : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -144,7 +144,7 @@ public class Retributionist : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.MeetingKillButton.png", 140f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => RetributionistOnClick(pva.TargetPlayerId))); + button.OnClick.AddListener((Action)(() => RetributionistOnClick(pva.PlayerId))); } } diff --git a/Roles/Standard/Crewmate/Power/CopyCat.cs b/Roles/Standard/Crewmate/Power/CopyCat.cs index c41e5043d..c3469918c 100644 --- a/Roles/Standard/Crewmate/Power/CopyCat.cs +++ b/Roles/Standard/Crewmate/Power/CopyCat.cs @@ -135,7 +135,7 @@ public class CopyCat : RoleBase CustomRoles.Workaholic or CustomRoles.Pawn => CustomRoles.Snitch, CustomRoles.Sunnyboy or CustomRoles.Fabricator => new[] {CustomRoles.Doctor, CustomRoles.ScientistEHR}.RandomElement(), CustomRoles.Vindicator or CustomRoles.Pickpocket => CustomRoles.Mayor, - CustomRoles.Councillor or CustomRoles.Magistrate => CustomRoles.Judge, + CustomRoles.Councillor or CustomRoles.Magistrate => CustomRoles.JudgeOld, CustomRoles.EvilGuesser or CustomRoles.Doomsayer or CustomRoles.NecroGuesser or CustomRoles.Augur => CustomRoles.NiceGuesser, CustomRoles.Vengeance => CustomRoles.Adrenaline, CustomRoles.Occultist => CustomRoles.Altruist, diff --git a/Roles/Standard/Crewmate/Power/President.cs b/Roles/Standard/Crewmate/Power/President.cs index b0ea71d50..89e44c0fd 100644 --- a/Roles/Standard/Crewmate/Power/President.cs +++ b/Roles/Standard/Crewmate/Power/President.cs @@ -206,7 +206,7 @@ public class President : RoleBase Utils.SendMessage("\n", pc.PlayerId, Utils.GetRemainingKillers(showAll: true), importance: MessageImportance.High); break; case Decree.GovernmentRecruiting: - if (MeetingHud.Instance?.playerStates?.FirstOrDefault(x => x.TargetPlayerId == pc.PlayerId)?.DidVote == true) return; + if (MeetingHud.Instance?.playerStates?.FirstOrDefault(x => x.PlayerId == pc.PlayerId)?.DidVote == true) return; president.IsRecruiting = true; break; diff --git a/Roles/Standard/Crewmate/Power/Swapper.cs b/Roles/Standard/Crewmate/Power/Swapper.cs index 1f392730f..d6ddaa776 100644 --- a/Roles/Standard/Crewmate/Power/Swapper.cs +++ b/Roles/Standard/Crewmate/Power/Swapper.cs @@ -277,7 +277,7 @@ public class Swapper : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -286,14 +286,14 @@ public class Swapper : RoleBase targetBox.transform.localPosition = new(-0.35f, 0.03f, -1.31f); var renderer = targetBox.GetComponent(); - if (pc.PlayerId == pva.TargetPlayerId && (SwapTargets.Item1 == pc.PlayerId || SwapTargets.Item2 == pc.PlayerId)) + if (pc.PlayerId == pva.PlayerId && (SwapTargets.Item1 == pc.PlayerId || SwapTargets.Item2 == pc.PlayerId)) renderer.sprite = CustomButton.Get("SwapYes"); else renderer.sprite = CustomButton.Get("SwapNo"); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => SwapperOnClick(pva.TargetPlayerId, __instance))); + button.OnClick.AddListener((Action)(() => SwapperOnClick(pva.PlayerId, __instance))); } } diff --git a/Roles/Standard/Crewmate/Support/Negotiator.cs b/Roles/Standard/Crewmate/Support/Negotiator.cs index 132cafdd0..2ecf76186 100644 --- a/Roles/Standard/Crewmate/Support/Negotiator.cs +++ b/Roles/Standard/Crewmate/Support/Negotiator.cs @@ -129,7 +129,7 @@ public class Negotiator : RoleBase if (Starspawn.IsDayBreak) return false; if (target == null || voter == null || voter.PlayerId == target.PlayerId || TargetId != byte.MaxValue || voter.GetAbilityUseLimit() < 1f || MinVotingTimeLeftToNegotiate.GetInt() > MeetingTimeManager.VotingTimeLeft || Main.DontCancelVoteList.Contains(voter.PlayerId)) return false; - bool votedLast = MeetingHud.Instance.playerStates.All(x => x.TargetPlayerId == voter.PlayerId || x.DidVote); + bool votedLast = MeetingHud.Instance.playerStates.All(x => x.PlayerId == voter.PlayerId || x.DidVote); TargetId = target.PlayerId; Penalty = votedLast ? NegotiationType.HarmfulAddon : NegotiationType.Suicide; diff --git a/Roles/Standard/Crewmate/Vanilla/CrewmateVanillaRoles.cs b/Roles/Standard/Crewmate/Vanilla/CrewmateVanillaRoles.cs index f354bf875..34d108d40 100644 --- a/Roles/Standard/Crewmate/Vanilla/CrewmateVanillaRoles.cs +++ b/Roles/Standard/Crewmate/Vanilla/CrewmateVanillaRoles.cs @@ -15,6 +15,7 @@ internal class CrewmateVanillaRoles : IVanillaSettingHolder public static OptionItem TrackerDuration; public static OptionItem TrackerDelay; public static OptionItem DetectiveSuspectLimit; + public static OptionItem JudgeTaskRequirementPercentage; public TabGroup Tab => TabGroup.CrewmateRoles; public void SetupCustomOption() @@ -72,5 +73,11 @@ internal class CrewmateVanillaRoles : IVanillaSettingHolder DetectiveSuspectLimit = new FloatOptionItem(5082, "DetectiveSuspectLimit", new(0f, 30f, 1f), 4f, Tab) .SetParent(CustomRoleSpawnChances[CustomRoles.DetectiveEHR]) .SetValueFormat(OptionFormat.Players); + + SetupRoleOptions(5090, Tab, CustomRoles.JudgeEHR); + + JudgeTaskRequirementPercentage = new FloatOptionItem(5092, "JudgeTaskRequirementPercentage", new(0f, 100f, 25f), 50f, Tab) + .SetParent(CustomRoleSpawnChances[CustomRoles.JudgeEHR]) + .SetValueFormat(OptionFormat.Percent); } } \ No newline at end of file diff --git a/Roles/Standard/Impostor/Concealing/Forger.cs b/Roles/Standard/Impostor/Concealing/Forger.cs index 24375082a..9e63a47a9 100644 --- a/Roles/Standard/Impostor/Concealing/Forger.cs +++ b/Roles/Standard/Impostor/Concealing/Forger.cs @@ -39,7 +39,7 @@ public class Forger : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -50,7 +50,7 @@ public class Forger : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.ForgerIcon.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.TargetPlayerId, __instance, true))); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.PlayerId, __instance, true))); } } diff --git a/Roles/Standard/Impostor/Killing/Assumer.cs b/Roles/Standard/Impostor/Killing/Assumer.cs index 332264366..659bbfa96 100644 --- a/Roles/Standard/Impostor/Killing/Assumer.cs +++ b/Roles/Standard/Impostor/Killing/Assumer.cs @@ -73,8 +73,8 @@ public class Assumer : RoleBase { foreach (PlayerVoteArea pva in MeetingHud.Instance.playerStates) { - if (pva.VotedFor == instance.Assumption.Id || (VoteReceiverDies.GetBool() && pva.TargetPlayerId == instance.Assumption.Id)) - CheckForEndVotingPatch.TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.Assumed, pva.TargetPlayerId); + if (pva.VotedForId == instance.Assumption.Id || (VoteReceiverDies.GetBool() && pva.PlayerId == instance.Assumption.Id)) + CheckForEndVotingPatch.TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.Assumed, pva.PlayerId); } } diff --git a/Roles/Standard/Impostor/Killing/Councillor.cs b/Roles/Standard/Impostor/Killing/Councillor.cs index de30d4f08..459812c6c 100644 --- a/Roles/Standard/Impostor/Killing/Councillor.cs +++ b/Roles/Standard/Impostor/Killing/Councillor.cs @@ -206,7 +206,7 @@ public class Councillor : RoleBase LateTask.New(() => { if (!MakeEvilJudgeClear.GetBool()) - Utils.SendMessage(string.Format(GetString("TrialKill"), name), 255, CustomRoles.Judge.ColoredTextByRole(GetString("TrialKillTitle")), importance: MessageImportance.High); + Utils.SendMessage(string.Format(GetString("TrialKill"), name), 255, CustomRoles.JudgeOld.ColoredTextByRole(GetString("TrialKillTitle")), importance: MessageImportance.High); else Utils.SendMessage(string.Format(GetString("MurderKill"), name), 255, CustomRoles.Councillor.ColoredTextByRole(GetString("MurderKillTitle")), importance: MessageImportance.High); }, 0.6f, "Guess Msg"); @@ -291,7 +291,7 @@ public class Councillor : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -302,7 +302,7 @@ public class Councillor : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.MeetingKillButton.png", 140f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => CouncillorOnClick(pva.TargetPlayerId /*, __instance*/))); + button.OnClick.AddListener((Action)(() => CouncillorOnClick(pva.PlayerId /*, __instance*/))); } } diff --git a/Roles/Standard/Impostor/Killing/Nemesis.cs b/Roles/Standard/Impostor/Killing/Nemesis.cs index 53424975e..90573934e 100644 --- a/Roles/Standard/Impostor/Killing/Nemesis.cs +++ b/Roles/Standard/Impostor/Killing/Nemesis.cs @@ -203,7 +203,7 @@ internal class Nemesis : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -214,7 +214,7 @@ internal class Nemesis : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.MeetingKillButton.png", 140f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => NemesisOnClick(pva.TargetPlayerId))); + button.OnClick.AddListener((Action)(() => NemesisOnClick(pva.PlayerId))); } } diff --git a/Roles/Standard/Impostor/Miscellaneous/Changeling.cs b/Roles/Standard/Impostor/Miscellaneous/Changeling.cs index 3c272e5a5..fef9970d8 100644 --- a/Roles/Standard/Impostor/Miscellaneous/Changeling.cs +++ b/Roles/Standard/Impostor/Miscellaneous/Changeling.cs @@ -146,9 +146,9 @@ internal class Changeling : RoleBase public static void CreateChangelingButton(MeetingHud __instance) { PlayerVoteArea localPva = __instance.playerStates - .FirstOrDefault(pva => pva.TargetPlayerId == PlayerControl.LocalPlayer.PlayerId); + .FirstOrDefault(pva => pva.PlayerId == PlayerControl.LocalPlayer.PlayerId); - PlayerControl pc = Utils.GetPlayerById(localPva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(localPva.PlayerId); if (!pc || !pc.IsAlive()) return; GameObject template = localPva.Buttons.transform.Find("CancelButton").gameObject; @@ -159,7 +159,7 @@ internal class Changeling : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.GlitchMimic.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(localPva.TargetPlayerId, __instance, true))); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(localPva.PlayerId, __instance, true))); } //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] diff --git a/Roles/Standard/Impostor/Miscellaneous/Loner.cs b/Roles/Standard/Impostor/Miscellaneous/Loner.cs index 9b7a3cb6b..073430529 100644 --- a/Roles/Standard/Impostor/Miscellaneous/Loner.cs +++ b/Roles/Standard/Impostor/Miscellaneous/Loner.cs @@ -62,7 +62,7 @@ public class Loner : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -73,7 +73,7 @@ public class Loner : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Sidekick.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.TargetPlayerId, __instance, true))); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.PlayerId, __instance, true))); } } diff --git a/Roles/Standard/Impostor/Support/Gangster.cs b/Roles/Standard/Impostor/Support/Gangster.cs index 82a3b2e45..684c94b79 100644 --- a/Roles/Standard/Impostor/Support/Gangster.cs +++ b/Roles/Standard/Impostor/Support/Gangster.cs @@ -121,7 +121,7 @@ public class Gangster : RoleBase (pc.Is(CustomRoles.Sheriff) && !SheriffCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Mayor) && !MayorCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.NiceGuesser) && !NGuesserCanBeMadmate.GetBool()) || - (pc.Is(CustomRoles.Judge) && !JudgeCanBeMadmate.GetBool()) || + (pc.Is(CustomRoles.JudgeOld) && !JudgeCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Marshall) && !MarshallCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Investigator) && !InvestigatorCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.President) && !PresidentCanBeMadmate.GetBool()) || diff --git a/Roles/Standard/Impostor/Support/Ventriloquist.cs b/Roles/Standard/Impostor/Support/Ventriloquist.cs index cfc229a5e..a3ee7a51b 100644 --- a/Roles/Standard/Impostor/Support/Ventriloquist.cs +++ b/Roles/Standard/Impostor/Support/Ventriloquist.cs @@ -62,7 +62,7 @@ public class Ventriloquist : RoleBase { foreach (PlayerVoteArea pva in __instance.playerStates) { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (!pc || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; @@ -73,7 +73,7 @@ public class Ventriloquist : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Hack.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => VentriloquistOnClick(pva.TargetPlayerId))); + button.OnClick.AddListener((Action)(() => VentriloquistOnClick(pva.PlayerId))); } } diff --git a/Roles/Standard/Neutral/Benign/Pawn.cs b/Roles/Standard/Neutral/Benign/Pawn.cs index ee2d414de..3be77964e 100644 --- a/Roles/Standard/Neutral/Benign/Pawn.cs +++ b/Roles/Standard/Neutral/Benign/Pawn.cs @@ -65,9 +65,9 @@ public class Pawn : RoleBase public static void CreatePawnButton(MeetingHud __instance) { PlayerVoteArea localPva = __instance.playerStates - .FirstOrDefault(pva => pva.TargetPlayerId == PlayerControl.LocalPlayer.PlayerId); + .FirstOrDefault(pva => pva.PlayerId == PlayerControl.LocalPlayer.PlayerId); - PlayerControl pc = Utils.GetPlayerById(localPva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(localPva.PlayerId); if (!pc || !pc.IsAlive()) return; GameObject template = localPva.Buttons.transform.Find("CancelButton").gameObject; @@ -78,7 +78,7 @@ public class Pawn : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.PawnPromotion.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(localPva.TargetPlayerId, __instance, true))); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(localPva.PlayerId, __instance, true))); } //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] diff --git a/Roles/Standard/Neutral/Evil/Collector.cs b/Roles/Standard/Neutral/Evil/Collector.cs index 9d7ffc87f..bf183de1a 100644 --- a/Roles/Standard/Neutral/Evil/Collector.cs +++ b/Roles/Standard/Neutral/Evil/Collector.cs @@ -113,7 +113,7 @@ public class Collector : RoleBase public static void CollectorVotes(PlayerControl target, PlayerVoteArea ps) //集票者投票给谁 { - if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.Collector)) CollectorVoteFor.TryAdd(target.PlayerId, ps.TargetPlayerId); + if (CheckForEndVotingPatch.CheckRole(ps.PlayerId, CustomRoles.Collector)) CollectorVoteFor.TryAdd(target.PlayerId, ps.PlayerId); } public static void CollectAmount(Dictionary VotingData, MeetingHud __instance) //得到集票者收集到的票 @@ -122,7 +122,7 @@ public class Collector : RoleBase { if (pva == null) continue; - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + PlayerControl pc = Utils.GetPlayerById(pva.PlayerId); if (pc == null) continue; foreach ((byte key, int value) in VotingData)