diff --git a/Gamemodes/KingOfTheZones.cs b/Gamemodes/KingOfTheZones.cs index 5aff60ab0..0ded7d31c 100644 --- a/Gamemodes/KingOfTheZones.cs +++ b/Gamemodes/KingOfTheZones.cs @@ -251,7 +251,7 @@ public static class KingOfTheZones AllRooms.RemoveWhere(x => x.ToString().Contains("Decontamination")); if (SubmergedCompatibility.IsSubmerged()) AllRooms.RemoveWhere(x => (byte)x > 135); - Zones = Main.LIMap ? ShipStatus.Instance.AllRooms.Select(x => x.RoomId).TakeRandomToList(NumZones.GetInt()) : DefaultZones[Main.CurrentMap][NumZones.GetInt() - 1]; + Zones = Main.LIMap ? ShipStatus.Instance.AllRooms.Select(x => x.RoomId).TakeRandom(NumZones.GetInt()) : DefaultZones[Main.CurrentMap][NumZones.GetInt() - 1]; Points = AllKOTZTeam.ToDictionary(x => x, _ => 0); PlayerPoints = Main.PlayerStates.Keys.ToDictionary(x => x, _ => 0); @@ -753,13 +753,14 @@ public static class KingOfTheZones { if (Zones.Count > 0 && ZoneMoveSchedules.TryGetValue(Zones[0], out long moveTS) && moveTS <= now) { - IEnumerable newZones = AllRooms.Except(Zones).TakeRandom(Zones.Count); + List newZones = AllRooms.Except(Zones).TakeRandom(Zones.Count); Zones.Clear(); ZoneDomination.Clear(); - foreach (SystemTypes newZone in newZones) + for (var index = 0; index < newZones.Count; index++) { + SystemTypes newZone = newZones[index]; Zones.Add(newZone); ZoneDomination[newZone] = KOTZTeam.None; ZoneMoveSchedules[newZone] = now + moveTime + downtime; diff --git a/Modules/Extensions/CollectionExtensions.cs b/Modules/Extensions/CollectionExtensions.cs index 05abb8cd3..85db2d463 100644 --- a/Modules/Extensions/CollectionExtensions.cs +++ b/Modules/Extensions/CollectionExtensions.cs @@ -227,45 +227,12 @@ public static class CollectionExtensions return false; } - /// - /// Takes the specified number of random elements from the collection to a List, and yields its elements for enumeration. - /// - /// The number of random elements to pick. - /// A new collection with the specified number of random elements from the original collection. - public IEnumerable TakeRandom(int count) - { - if (collection == null || count <= 0) - yield break; - - var reservoir = new List(count); - int i = 0; - - foreach (var item in collection) - { - if (i < count) - { - reservoir.Add(item); - } - else - { - int j = IRandom.Instance.Next(i + 1); - if (j < count) - reservoir[j] = item; - } - i++; - } - - // yield instead of returning list to avoid extra allocation - foreach (var item in reservoir) - yield return item; - } - /// /// Takes the specified number of random elements from the collection, and adds them to a new List. /// /// The number of random elements to pick. /// A new List with the specified number of random elements from the original collection. - public List TakeRandomToList(int count) + public List TakeRandom(int count) { if (collection == null || count <= 0) return []; diff --git a/Modules/GameState.cs b/Modules/GameState.cs index f87efe841..b63f7affd 100644 --- a/Modules/GameState.cs +++ b/Modules/GameState.cs @@ -155,12 +155,8 @@ public class PlayerState(byte playerId) Main.AbilityUseLimit.Remove(PlayerId); } - if (!AmongUsClient.Instance.AmHost) return; - if (Main.IntroDestroyed && GameStates.InGame) { - Player.ResetKillCooldown(); - if (PlayerId == PlayerControl.LocalPlayer.PlayerId && GameStates.IsInTask) { HudManager.Instance.SetHudActive(true); @@ -168,6 +164,10 @@ public class PlayerState(byte playerId) HudSpritePatch.ForceUpdate = true; } + if (!AmongUsClient.Instance.AmHost) return; + + Player.ResetKillCooldown(); + if (Decryptor.On) Decryptor.Instances.ForEach(x => x.OnRoleChange(PlayerId)); if (!role.Is(Team.Impostor) && !(role == CustomRoles.Traitor && Traitor.CanGetImpostorOnlyAddons.GetBool())) @@ -191,6 +191,8 @@ public class PlayerState(byte playerId) Utils.NotifyRoles(SpecifyTarget: Player); } + if (!AmongUsClient.Instance.AmHost) return; + CheckMurderPatch.TimeSinceLastKill.Remove(PlayerId); if (!Main.IntroDestroyed || PlayerControl.LocalPlayer.PlayerId != PlayerId || Options.CurrentGameMode != CustomGameMode.Standard) return; diff --git a/Modules/NameNotifyManager.cs b/Modules/NameNotifyManager.cs index 323f8c2f9..79016ec6f 100644 --- a/Modules/NameNotifyManager.cs +++ b/Modules/NameNotifyManager.cs @@ -64,7 +64,7 @@ public static class NameNotifyManager if (now == LastUpdate) return; LastUpdate = now; - if (!AmongUsClient.Instance.AmHost || Notifies.Count == 0) return; + if (Notifies.Count == 0) return; var notifyEnumerator = Notifies.GetEnumerator(); while (notifyEnumerator.MoveNext()) @@ -88,6 +88,8 @@ public static class NameNotifyManager { for (int index = 0; index < toRemove.Count; index++) dict.Remove(toRemove[index]); + + if (!AmongUsClient.Instance.AmHost) continue; PlayerControl pc = Utils.GetPlayerById(id); if (pc.IsAlive()) Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 19b028604..b4a3cbaa7 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -3492,7 +3492,8 @@ public static class Options public static void SetupSingleRoleOptions(int id, TabGroup tab, CustomRoles role, int count = 1, CustomGameMode customGameMode = CustomGameMode.Standard, bool zeroOne = false, bool hideMaxSetting = true) { - var spawnOption = new StringOptionItem(id, role.ToString(), zeroOne ? RatesZeroOne : Rates, 0, tab).SetColor(Utils.GetRoleColor(role)) + var spawnOption = new StringOptionItem(id, role.ToString(), zeroOne ? RatesZeroOne : Rates, 0, tab) + .SetColor(Utils.GetRoleColor(role)) .SetHeader(true) .SetGameMode(customGameMode) as StringOptionItem; diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 7830e5f5e..01acfbe46 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -1221,7 +1221,7 @@ public static class Utils void CheckAndAppendOptionString(OptionItem item) { - if (item.GetBool() && item.Parent == null && !item.IsCurrentlyHidden()) + if (item.GetBool() && item.Parent == null && !item.IsCurrentlyHidden(checkCollapsedSection: false)) sb.Append($"\n{item.GetName(true)}: {item.GetString()}"); } } @@ -1266,7 +1266,7 @@ public static class Utils foreach (OptionItem opt in OptionItem.AllOptions) { - if (opt.GetBool() && opt.Parent == null && opt.Id is >= 80000 and < 640000 && !opt.IsCurrentlyHidden()) + if (opt.GetBool() && opt.Parent == null && opt.Id is >= 80000 and < 640000 && !opt.IsCurrentlyHidden(checkCollapsedSection: false)) { if (opt.Name is "KillFlashDuration" or "RoleAssigningAlgorithm") sb.Append($"\n【{opt.GetName(true)}: {opt.GetString()}】\n"); @@ -1314,7 +1314,7 @@ public static class Utils sb.Append($"━━━━━━━━━━━━【{GetString("Settings")}】━━━━━━━━━━━━"); - foreach (OptionItem opt in OptionItem.AllOptions.Where(x => x.GetBool() && x.Parent == null && x.Id is >= 80000 and < 640000 && !x.IsCurrentlyHidden())) + foreach (OptionItem opt in OptionItem.AllOptions.Where(x => x.GetBool() && x.Parent == null && x.Id is >= 80000 and < 640000 && !x.IsCurrentlyHidden(checkCollapsedSection: false))) { if (opt.Name == "KillFlashDuration") sb.Append($"\n【{opt.GetName(true)}: {opt.GetString()}】\n"); diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 4a0506de0..4e30546ac 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -1491,7 +1491,7 @@ internal static class ChatCommands } 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(); + List allRoles = Main.CustomRoleValues.Where(x => x < CustomRoles.NotAssigned && x.IsEnable() && !x.IsForOtherGameMode() && !x.IsVanilla() && x is not CustomRoles.GM && !ShouldNotSpawn(x) && (!rollSpawnChance || IRandom.Instance.Next(100) < x.GetMode())).Shuffle(); if (allRoles.Count < allPlayerIds.Length) { @@ -1499,18 +1499,15 @@ internal static class ChatCommands return; } - IEnumerable impRoles = allRoles.Where(x => x.IsImpostor()).TakeRandom(Options.FactionMinMaxSettings[Team.Impostor].MaxSetting.GetInt()); - IEnumerable nkRoles = allRoles.Where(x => x.IsNK()).TakeRandom(Math.Min(Options.FactionMinMaxSettings[Team.Neutral].MaxSetting.GetInt(), Options.RoleSubCategoryLimits[RoleOptionType.Neutral_Killing][2].GetInt())); - IEnumerable nnkRoles = allRoles.Where(x => x.IsNonNK()).TakeRandom(Math.Min(Options.FactionMinMaxSettings[Team.Neutral].MaxSetting.GetInt() - Options.RoleSubCategoryLimits[RoleOptionType.Neutral_Killing][2].GetInt(), Options.MaxNNKs.GetInt())); - IEnumerable covenRoles = allRoles.Where(x => x.IsCoven()).TakeRandom(Options.FactionMinMaxSettings[Team.Coven].MaxSetting.GetInt()); + List impRoles = allRoles.Where(x => x.IsImpostor()).TakeRandom(Options.FactionMinMaxSettings[Team.Impostor].MaxSetting.GetInt()); + List nkRoles = allRoles.Where(x => x.IsNK()).TakeRandom(Math.Min(Options.FactionMinMaxSettings[Team.Neutral].MaxSetting.GetInt(), Options.RoleSubCategoryLimits[RoleOptionType.Neutral_Killing][2].GetInt())); + List nnkRoles = allRoles.Where(x => x.IsNonNK()).TakeRandom(Math.Min(Options.FactionMinMaxSettings[Team.Neutral].MaxSetting.GetInt() - Options.RoleSubCategoryLimits[RoleOptionType.Neutral_Killing][2].GetInt(), Options.MaxNNKs.GetInt())); + List covenRoles = allRoles.Where(x => x.IsCoven()).TakeRandom(Options.FactionMinMaxSettings[Team.Coven].MaxSetting.GetInt()); - allRoles.RemoveAll(x => x.IsImpostor()); - allRoles.RemoveAll(x => x.IsNK()); - allRoles.RemoveAll(x => x.IsNonNK()); - allRoles.RemoveAll(x => x.IsCoven()); + allRoles.RemoveAll(x => x.IsImpostor() || x.IsNK() || x.IsNonNK() || x.IsCoven()); DraftRoles = allRoles - .Take(allPlayerIds.Length * maxRolesPerPlayer) + .Take(allPlayerIds.Length * maxRolesPerPlayer - impRoles.Count - nkRoles.Count - nnkRoles.Count - covenRoles.Count) .CombineWith(impRoles, nkRoles, nnkRoles, covenRoles) .Shuffle() .Partition(allPlayerIds.Length) diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs index d0edba9c1..cb5508dff 100644 --- a/Patches/IntroPatch.cs +++ b/Patches/IntroPatch.cs @@ -410,7 +410,7 @@ internal static class SetUpRoleTextPatch foreach (OptionItem o in options) { - if (!o.IsCurrentlyHidden() && (o.Parent == null ? !o.GetString().Equals(disabledRoleStr) : AllParentsEnabled(o))) + if (!o.IsCurrentlyHidden(checkCollapsedSection: false) && (o.Parent == null ? !o.GetString().Equals(disabledRoleStr) : AllParentsEnabled(o))) sb.Append($"{(o.Parent == null ? o.GetName(true, true).RemoveHtmlTags().PadRightV2(40) : $"┗ {o.GetName(true, true).RemoveHtmlTags()}".PadRightV2(41))}:{o.GetString().RemoveHtmlTags()}\n"); if (i++ > 20) @@ -1420,7 +1420,7 @@ internal static class IntroCutsceneDestroyPatch if (Options.CurrentGameMode is CustomGameMode.Standard or CustomGameMode.HideAndSeek && !Utils.HasTasks(PlayerControl.LocalPlayer.Data, forRecompute: false)) hud.TaskPanel.open = false; - if (!AmongUsClient.Instance.AmHost || !Lovers.PrivateChat.GetBool()) return; + if (!AmongUsClient.Instance.AmHost || !Lovers.PrivateChat.GetBool() || Options.ChatDuringGame.GetBool()) return; Main.LoversPlayers.SetChatVisible(true); }, 1f, log: false); diff --git a/Patches/OnGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs index 9b1c662c8..1ba5e635d 100644 --- a/Patches/OnGameStartedPatch.cs +++ b/Patches/OnGameStartedPatch.cs @@ -798,7 +798,7 @@ internal static class StartGameHostPatch roleList.ExceptWith(otherList); } - BasisChangingAddons[addon] = roleList.TakeRandomToList(addon.GetCount()); + BasisChangingAddons[addon] = roleList.TakeRandom(addon.GetCount()); } } } diff --git a/Resources/Lang/en_US.jsonc b/Resources/Lang/en_US.jsonc index ef42abfc1..e727a20c0 100644 --- a/Resources/Lang/en_US.jsonc +++ b/Resources/Lang/en_US.jsonc @@ -24,7 +24,7 @@ "SayTitle": "★[ Moderator message ]★", "announcementUpdate": "Update v{0}\\n{1}", "announcementChangelog": "ChangeLogs v{0}\\n{1}", - "Server": "<#00ffa5>Server:: ", + "Server": "<#00ffa5>Server: ", "VersionMismatch": "{0} has a different version of the mod installed", "ModMismatch": "{0} has a different mod installed that isn't compatible with EHR <#ffff00>⚠", "PrivacyPolicy": "Have you read and agree to the Privacy Policy and Code Of Conduct available on the mod's official GitHub repository?\\nYou must accept them to continue.", diff --git a/Roles/Standard/Crewmate/Investigate/Snitch.cs b/Roles/Standard/Crewmate/Investigate/Snitch.cs index ef5f01f03..42ed47dbf 100644 --- a/Roles/Standard/Crewmate/Investigate/Snitch.cs +++ b/Roles/Standard/Crewmate/Investigate/Snitch.cs @@ -80,17 +80,11 @@ public class Snitch : RoleBase IsComplete.Remove(playerId); } - private static bool IsSnitch(byte playerId) - { - return PlayerIdList.Contains(playerId); - } - private static bool GetExpose(PlayerControl pc) { - if (!IsSnitch(pc.PlayerId) || !pc.IsAlive() || pc.Is(CustomRoles.Madmate)) return false; + if (!pc.IsAlive() || pc.Is(CustomRoles.Madmate)) return false; - byte snitchId = pc.PlayerId; - return IsExposed[snitchId]; + return IsExposed.GetValueOrDefault(pc.PlayerId); } public static bool IsSnitchTarget(PlayerControl target) @@ -98,51 +92,6 @@ public class Snitch : RoleBase return (target.Is(CustomRoleTypes.Impostor) && !target.Is(CustomRoles.Trickster)) || (target.IsNeutralKiller() && CanFindNeutralKiller) || (target.Is(CustomRoleTypes.Coven) && CanFindCoven) || (target.Is(CustomRoles.Madmate) && CanFindMadmate) || (target.Is(CustomRoles.Rascal) && CanFindMadmate); } - private static void CheckTask(PlayerControl snitch) - { - if (!snitch.IsAlive() || snitch.Is(CustomRoles.Madmate) || snitch.IsConverted()) return; - - byte snitchId = snitch.PlayerId; - TaskState snitchTask = snitch.GetTaskState(); - - if (!IsExposed[snitchId] && snitchTask.RemainingTasksCount <= RemainingTasksToBeFound) - { - foreach (PlayerControl target in Main.CachedAlivePlayerControls()) - { - if (!IsSnitchTarget(target)) continue; - TargetArrow.Add(target.PlayerId, snitchId); - Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: target); - } - - IsExposed[snitchId] = true; - } - - if (IsComplete[snitchId] || !snitchTask.IsTaskFinished) return; - - foreach (PlayerControl target in Main.CachedAlivePlayerControls()) - { - if (!IsSnitchTarget(target)) continue; - - byte targetId = target.PlayerId; - NameColorManager.Add(snitchId, targetId); - - if (!EnableTargetArrow) continue; - - TargetArrow.Add(snitchId, targetId); - - if (TargetList.Add(targetId)) - { - if (CanGetColoredArrow) - TargetColorlist.Add(targetId, target.GetRoleColor()); - } - - Utils.NotifyRoles(SpecifySeer: snitch, SpecifyTarget: target); - } - - snitch.Notify(Translator.GetString("SnitchDoneTasks")); - IsComplete[snitchId] = true; - } - public static string GetWarningMark(PlayerControl seer, PlayerControl target) { return IsSnitchTarget(seer) && GetExpose(target) ? Utils.ColorString(RoleColor, " ★") : string.Empty; @@ -183,8 +132,43 @@ public class Snitch : RoleBase public override void OnTaskComplete(PlayerControl pc, int completedTaskCount, int totalTaskCount) { - if (!IsSnitch(pc.PlayerId) || pc.Is(CustomRoles.Madmate)) return; + if (!pc.IsAlive() || pc.IsConverted() || pc.Is(CustomRoles.Madmate)) return; - CheckTask(pc); + if (!IsExposed.GetValueOrDefault(pc.PlayerId) && totalTaskCount - (completedTaskCount + 1) <= RemainingTasksToBeFound) + { + foreach (PlayerControl target in Main.CachedAlivePlayerControls()) + { + if (!IsSnitchTarget(target)) continue; + TargetArrow.Add(target.PlayerId, pc.PlayerId); + Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: target); + } + + IsExposed[pc.PlayerId] = true; + } + + if (IsComplete.GetValueOrDefault(pc.PlayerId) || completedTaskCount + 1 < totalTaskCount) return; + + IsComplete[pc.PlayerId] = true; + pc.Notify(Translator.GetString("SnitchDoneTasks")); + + foreach (PlayerControl target in Main.CachedAlivePlayerControls()) + { + if (!IsSnitchTarget(target)) continue; + + byte targetId = target.PlayerId; + NameColorManager.Add(pc.PlayerId, targetId); + + if (!EnableTargetArrow) continue; + + TargetArrow.Add(pc.PlayerId, targetId); + + if (TargetList.Add(targetId)) + { + if (CanGetColoredArrow) + TargetColorlist.Add(targetId, target.GetRoleColor()); + } + + Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: target); + } } } \ No newline at end of file diff --git a/Roles/Standard/Crewmate/Killing/Sheriff.cs b/Roles/Standard/Crewmate/Killing/Sheriff.cs index 18b1c5915..e047e87b5 100644 --- a/Roles/Standard/Crewmate/Killing/Sheriff.cs +++ b/Roles/Standard/Crewmate/Killing/Sheriff.cs @@ -125,7 +125,7 @@ public class Sheriff : RoleBase public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { - if (CanBeKilledBySheriff(target) || SidekickSheriffCanGoBerserk.GetBool() || (SetNonCrewCanKill.GetBool() && (killer.IsMadmate() || killer.IsConverted()) && ((target.IsImpostor() && NonCrewCanKillImp.GetBool()) || (target.IsCrewmate() && NonCrewCanKillCrew.GetBool()) || (target.GetCustomRole().IsNeutral() && NonCrewCanKillNeutral.GetBool())))) + if (CanBeKilledBySheriff(target) || (SidekickSheriffCanGoBerserk.GetBool() && killer.Is(CustomRoles.Sidekick)) || (SetNonCrewCanKill.GetBool() && (killer.IsMadmate() || killer.IsConverted()) && ((target.IsImpostor() && NonCrewCanKillImp.GetBool()) || (target.IsCrewmate() && NonCrewCanKillCrew.GetBool()) || (target.GetCustomRole().IsNeutral() && NonCrewCanKillNeutral.GetBool())))) { SetKillCooldown(killer.PlayerId); return true; diff --git a/Roles/Standard/Crewmate/Power/Survivor.cs b/Roles/Standard/Crewmate/Power/Survivor.cs index ea820fbf2..4267a6465 100644 --- a/Roles/Standard/Crewmate/Power/Survivor.cs +++ b/Roles/Standard/Crewmate/Power/Survivor.cs @@ -13,7 +13,7 @@ using static Utils; public class Survivor : RoleBase { - private const int Id = 7680; + private const int Id = 659000; public static bool On; public static OptionItem FirstAbility; @@ -34,23 +34,31 @@ public class Survivor : RoleBase { SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Survivor); - FirstAbility = new IntegerOptionItem(Id + 11, "SurvivorFirstAbility", new(0, 70, 1), 10, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); + FirstAbility = new IntegerOptionItem(Id + 11, "SurvivorFirstAbility", new(0, 70, 1), 10, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); - SecondAbility = new IntegerOptionItem(Id + 12, "SurvivorSecondAbility", new(0, 70, 1), 8, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); + SecondAbility = new IntegerOptionItem(Id + 12, "SurvivorSecondAbility", new(0, 70, 1), 8, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); - ThirdAbility = new IntegerOptionItem(Id + 13, "SurvivorThirdAbility", new(0, 70, 1), 6, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); + ThirdAbility = new IntegerOptionItem(Id + 13, "SurvivorThirdAbility", new(0, 70, 1), 6, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); - LastAbility = new IntegerOptionItem(Id + 14, "SurvivorLastAbility", new(0, 70, 1), 4, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); + LastAbility = new IntegerOptionItem(Id + 14, "SurvivorLastAbility", new(0, 70, 1), 4, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); - ShieldCooldown = new FloatOptionItem(Id + 15, "AidCD", new(0f, 70f, 1f), 15f, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]) + ShieldCooldown = new FloatOptionItem(Id + 15, "AidCD", new(0f, 70f, 1f), 15f, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]) .SetValueFormat(OptionFormat.Seconds); - ShieldDuration = new FloatOptionItem(Id + 16, "AidDur", new(5f, 70f, 1f), 20f, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]) + ShieldDuration = new FloatOptionItem(Id + 16, "AidDur", new(5f, 70f, 1f), 20f, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]) .SetValueFormat(OptionFormat.Seconds); - AdditionalVote = new IntegerOptionItem(Id + 17, "MayorAdditionalVote", new(0, 90, 1), 2, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); + AdditionalVote = new IntegerOptionItem(Id + 17, "MayorAdditionalVote", new(0, 90, 1), 2, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]); - KillCooldown = new FloatOptionItem(Id + 18, "KillCooldown", new(5f, 70f, 1f), 20f, TabGroup.CrewmateRoles).SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]) + KillCooldown = new FloatOptionItem(Id + 18, "KillCooldown", new(5f, 70f, 1f), 20f, TabGroup.CrewmateRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Survivor]) .SetValueFormat(OptionFormat.Seconds); } @@ -180,7 +188,10 @@ public class Survivor : RoleBase } } - public override bool CanUseKillButton(PlayerControl pc) { return Killing; } + public override bool CanUseKillButton(PlayerControl pc) + { + return Killing; + } public override void SetKillCooldown(byte id) { diff --git a/Roles/Standard/Crewmate/Support/TimeMaster.cs b/Roles/Standard/Crewmate/Support/TimeMaster.cs index 6fd7726ad..999a26996 100644 --- a/Roles/Standard/Crewmate/Support/TimeMaster.cs +++ b/Roles/Standard/Crewmate/Support/TimeMaster.cs @@ -24,7 +24,6 @@ internal class TimeMaster : RoleBase public static OptionItem TimeMasterAbilityChargesWhenFinishedTasks; public static OptionItem TimeMasterAbilityUseGainWithEachTaskCompleted; - private static Dictionary TargetPosition = []; private static Dictionary> BackTrack = []; private static List RevivedPlayers = []; public static bool Rewinding; @@ -82,7 +81,6 @@ internal class TimeMaster : RoleBase On = false; Rewinding = false; RevivedPlayers = []; - TargetPosition = []; BackTrack = []; } @@ -133,20 +131,20 @@ internal class TimeMaster : RoleBase private static IEnumerator Rewind() { + const float delay = 0.3f; + long now = Utils.TimeStamp; + int length = TimeMasterRewindTimeLength.GetInt(); + + Dictionary originalSpeeds = Main.AllPlayerSpeed.ToDictionary(x => x.Key, x => x.Value); + Main.AllPlayerSpeed.SetAllValues(Main.MinSpeed); + ReportDeadBodyPatch.CanReport.SetAllValues(false); + try { Rewinding = true; - const float delay = 0.3f; - long now = Utils.TimeStamp; - int length = TimeMasterRewindTimeLength.GetInt(); - - Dictionary originalSpeeds = Main.AllPlayerSpeed.ToDictionary(x => x.Key, x => x.Value); - Main.AllPlayerSpeed.SetAllValues(Main.MinSpeed); - ReportDeadBodyPatch.CanReport.SetAllValues(false); - string notify = Utils.ColorString(Color.yellow, string.Format(Translator.GetString("TimeMasterRewindStart"), CustomRoles.TimeMaster.ToColoredString())); - + foreach (PlayerControl player in Main.EnumeratePlayerControls()) { if (player.inVent || player.MyPhysics?.Animations?.IsPlayingEnterVentAnimation() == true) player.MyPhysics?.RpcExitVent(player.GetClosestVent().Id); @@ -199,11 +197,15 @@ internal class TimeMaster : RoleBase } } + + } + finally + { + Rewinding = false; Main.AllPlayerSpeed = originalSpeeds; ReportDeadBodyPatch.CanReport.SetAllValues(true); Utils.MarkEveryoneDirtySettings(); } - finally { Rewinding = false; } } public override void AfterMeetingTasks() @@ -218,16 +220,15 @@ internal class TimeMaster : RoleBase long now = Utils.TimeStamp; if (!BackTrack.TryAdd(now, null)) return; - TargetPosition.Clear(); - var alivePlayers = Main.CachedAlivePlayerControls(); + Dictionary targetPosition = []; - foreach (PlayerControl pc in alivePlayers) + foreach (PlayerControl pc in Main.CachedAlivePlayerControls()) { if (pc.inVent || pc.onLadder || pc.inMovingPlat) continue; - TargetPosition[pc.PlayerId] = pc.Pos(); + targetPosition[pc.PlayerId] = pc.Pos(); } - BackTrack[now] = TargetPosition; + BackTrack[now] = targetPosition; if (TimeMasterCanUseVitals.GetBool()) return; diff --git a/Roles/Standard/Neutral/Killing/Evolver.cs b/Roles/Standard/Neutral/Killing/Evolver.cs index b68f9c9de..d27617df5 100644 --- a/Roles/Standard/Neutral/Killing/Evolver.cs +++ b/Roles/Standard/Neutral/Killing/Evolver.cs @@ -118,7 +118,7 @@ public class Evolver : RoleBase { if (!EvolverPC.IsAlive()) return; - Upgrades = Enum.GetValues().Except(GetBannedUpgradeList()).TakeRandomToList(3); + Upgrades = Enum.GetValues().Except(GetBannedUpgradeList()).TakeRandom(3); SelectedUpgradeIndex = 0; ChooseTimer = 15; diff --git a/Roles/Standard/Neutral/Killing/SoulCollector.cs b/Roles/Standard/Neutral/Killing/SoulCollector.cs index 03b89a74e..f30150431 100644 --- a/Roles/Standard/Neutral/Killing/SoulCollector.cs +++ b/Roles/Standard/Neutral/Killing/SoulCollector.cs @@ -86,18 +86,8 @@ public class SoulCollector : RoleBase sender.SendMessage(); } - if (target.AmOwner) - { - Logger.Info("Host Exiled", "SoulCollector"); - target.Exiled(); - } - else - { - - var sender = CustomRpcSender.Create("SoulCollector Kill: Target", SendOption.Reliable); - sender.RpcExiled(target, targetClientId: target.OwnerId, exileForHost: false); - sender.SendMessage(); - } + Logger.Info("Desync Kill Target", "SoulCollector"); + target.RpcSetRoleDesync(target.GetGhostRoleBasis(), target.OwnerId); target.MarkDirtySettings(); return false; @@ -107,16 +97,12 @@ public class SoulCollector : RoleBase { if (ToExile.Count > 0) { - var sender = CustomRpcSender.Create("SoulCollector Post Exile", SendOption.Reliable); - sender.StartMessage(); - PlayerControl[] toExile = ToExile.ToValidPlayers().ToArray(); - ToExile = []; - toExile.Do(x => + ToExile.ToValidPlayers().Do(x => { Main.AllPlayerSpeed[x.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod); - sender.RpcExiled(x, autoStartRpc: false); + x.RpcSetRoleGlobal(x.GetGhostRoleBasis()); }); - sender.SendMessage(); + ToExile = []; } } } \ No newline at end of file diff --git a/Roles/Standard/Neutral/Killing/Thanos.cs b/Roles/Standard/Neutral/Killing/Thanos.cs index bf9362337..786519f43 100644 --- a/Roles/Standard/Neutral/Killing/Thanos.cs +++ b/Roles/Standard/Neutral/Killing/Thanos.cs @@ -58,7 +58,7 @@ public class Thanos : RoleBase CollectedStones = []; ActiveStone = null; MindStoneUsed = false; - PlayersWithStones = Main.EnumerateAlivePlayerControls().Select(x => x.PlayerId).TakeRandomToList(StoneEnum.Length); + PlayersWithStones = Main.EnumerateAlivePlayerControls().Select(x => x.PlayerId).TakeRandom(StoneEnum.Length); ThanosId = playerId; Instances.Add(this); } diff --git a/Roles/Standard/Neutral/Pariah/Magistrate.cs b/Roles/Standard/Neutral/Pariah/Magistrate.cs index 52f550c59..51ece76d6 100644 --- a/Roles/Standard/Neutral/Pariah/Magistrate.cs +++ b/Roles/Standard/Neutral/Pariah/Magistrate.cs @@ -1,6 +1,7 @@ using System.Collections; using AmongUs.GameOptions; using EHR.Modules; +using Hazel; using UnityEngine; namespace EHR.Roles; @@ -58,6 +59,7 @@ public class Magistrate : RoleBase if (CallCourtNextMeeting) { CallCourtNextMeeting = false; + Utils.SendRPC(CustomRPC.SyncRoleData, MagistrateID, CallCourtNextMeeting); Main.EnumeratePlayerControls().Do(x => Camouflage.RpcSetSkin(x, notCommsOrCamo: true)); } } @@ -103,6 +105,12 @@ public class Magistrate : RoleBase pc.RPCPlayCustomSound("Line"); pc.RpcRemoveAbilityUse(); CallCourtNextMeeting = true; + Utils.SendRPC(CustomRPC.SyncRoleData, pc.PlayerId, CallCourtNextMeeting); + } + + public void ReceiveRPC(MessageReader reader) + { + CallCourtNextMeeting = reader.ReadBoolean(); } private enum AbilityTriggers