diff --git a/Gamemodes/CustomHnS.cs b/Gamemodes/CustomHnS.cs index 5667ef300..16d9ac800 100644 --- a/Gamemodes/CustomHnS.cs +++ b/Gamemodes/CustomHnS.cs @@ -29,6 +29,7 @@ internal static class CustomHnS public static List AllHnSRoles = []; public static int SeekerNum => Math.Max(Main.RealOptionsData.GetInt(Int32OptionNames.NumImpostors), 1); + public static int RandomNeutralsNum => IRandom.Instance.Next(MinNeutrals.GetInt(), MaxNeutrals.GetInt() + 1); public static int MaximumGameLength => MaxGameLength.GetInt(); public static bool Chat => ChatDuringGame.GetBool(); @@ -134,7 +135,7 @@ internal static class CustomHnS Dictionary memberNum = new() { - [Team.Neutral] = IRandom.Instance.Next(MinNeutrals.GetInt(), MaxNeutrals.GetInt() + 1), + [Team.Neutral] = RandomNeutralsNum, [Team.Impostor] = SeekerNum }; @@ -142,7 +143,7 @@ internal static class CustomHnS Logger.Warn($"Number of impostors: {memberNum[Team.Impostor]}", "HnsRoleAssigner"); - foreach (KeyValuePair item in Main.SetRoles) + foreach (KeyValuePair item in Main.SetRoles.AddRange(ChatCommands.DraftResult, false)) { try { diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index c0118d36b..30ac0547f 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -1339,11 +1339,52 @@ internal static class ChatCommands public static void DraftStartCommand(PlayerControl player, string text, string[] args) { - if (Options.CurrentGameMode != CustomGameMode.Standard) return; + CustomGameMode gameMode = Options.CurrentGameMode; + + if (gameMode is not (CustomGameMode.Standard or CustomGameMode.HideAndSeek)) return; DraftResult = []; byte[] allPlayerIds = Main.EnumeratePlayerControls().Select(x => x.PlayerId).ToArray(); + int maxRolesPerPlayer = Options.DraftMaxRolesPerPlayer.GetInt(); + + if (gameMode == CustomGameMode.HideAndSeek) + { + List<(CustomRoles Role, IHideAndSeekRole Interface)> hnsRoles = CustomHnS.GetAllHnsRoleTypes().Select(x => (Enum.Parse(ignoreCase: true, value: x.Name), (IHideAndSeekRole)Activator.CreateInstance(x))).ToList(); + Dictionary memberNum = new() + { + [Team.Impostor] = Main.NormalOptions.NumImpostors, + [Team.Neutral] = CustomHnS.RandomNeutralsNum + }; + + foreach ((Team team, int num) in memberNum) + { + var seekerRoles = hnsRoles.FindAll(x => x.Interface.Team == team); + allPlayerIds.Shuffle().Where(x => !DraftRoles.ContainsKey(x)).Take(num).Do(x => DraftRoles[x] = [seekerRoles.RandomElement().Role]); + } + + var hiderRoles = hnsRoles.FindAll(x => x.Interface.Team == Team.Crewmate); + + while (true) + { + if (DraftRoles.Values.FindFirst(x => x.Count < maxRolesPerPlayer, out List roles)) + roles.Add(hiderRoles.RandomElement().Role); + else if (allPlayerIds.FindFirst(x => !DraftRoles.ContainsKey(x), out byte id)) + DraftRoles[id] = [hiderRoles.RandomElement().Role]; + else + break; + } + + foreach (List rolesList in DraftRoles.Values) + { + HashSet seen = []; + rolesList.RemoveAll(r => !seen.Add(r)); + } + + Main.Instance.StartCoroutine(RepeatedlySendMessage()); + return; + } + bool rollSpawnChance = Options.DraftAffectedByRoleSpawnChances.GetBool(); List allRoles = Main.CustomRoleValues.Where(x => x < CustomRoles.NotAssigned && x.IsEnable() && !x.IsForOtherGameMode() && !CustomHnS.AllHnSRoles.Contains(x) && !x.IsVanilla() && x is not CustomRoles.GM && !ShouldNotSpawn(x) && (!rollSpawnChance || IRandom.Instance.Next(100) < x.GetMode())).Shuffle(); @@ -1363,8 +1404,6 @@ internal static class ChatCommands allRoles.RemoveAll(x => x.IsNonNK()); allRoles.RemoveAll(x => x.IsCoven()); - int maxRolesPerPlayer = Options.DraftMaxRolesPerPlayer.GetInt(); - DraftRoles = allRoles .Take(allPlayerIds.Length * maxRolesPerPlayer) .CombineWith(impRoles, nkRoles, nnkRoles, covenRoles) @@ -1380,6 +1419,13 @@ internal static class ChatCommands { for (var index = 0; index < 3; index++) { + if (Options.CurrentGameMode is not (CustomGameMode.Standard or CustomGameMode.HideAndSeek)) + { + DraftRoles = []; + DraftResult = []; + yield break; + } + List messages = []; foreach ((byte id, List roles) in DraftRoles) diff --git a/Roles/Standard/Neutral/Killing/Werewolf.cs b/Roles/Standard/Neutral/Killing/Werewolf.cs index c527a73a7..2715cb763 100644 --- a/Roles/Standard/Neutral/Killing/Werewolf.cs +++ b/Roles/Standard/Neutral/Killing/Werewolf.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using AmongUs.GameOptions; +using EHR.Modules; using EHR.Modules.Extensions; using Hazel; using static EHR.Options; @@ -111,6 +112,7 @@ public class Werewolf : RoleBase RampageTimer = null; if (!AmongUsClient.Instance.AmHost || !pc) return; StartCooldownTimer(pc); + Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, false); pc.Notify(GetString("WWRampageOut")); if (!pc.IsModdedClient()) pc.RpcChangeRoleBasis(CustomRoles.CrewmateEHR); }, onTick: !AmongUsClient.Instance.AmHost || pc.IsModdedClient() ? null : () => pc.Notify(string.Format(GetString("WWRampageCountdown"), (int)RampageTimer.Remaining.TotalSeconds), overrideAll: true), onCanceled: () => RampageTimer = null); @@ -150,6 +152,7 @@ public class Werewolf : RoleBase var pc = WWId.GetPlayer(); if (!pc || !pc.IsAlive()) return; StartCooldownTimer(pc); + Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, false); } public override void OnExitVent(PlayerControl pc, Vent vent) @@ -186,6 +189,7 @@ public class Werewolf : RoleBase { KillsInLastRampage = 0; StartRampageTimer(pc); + Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, true); pc.Notify(GetString("WWRampaging"), RampageDur.GetFloat()); if (!pc.IsModdedClient()) pc.RpcChangeRoleBasis(CustomRoles.Werewolf); }