From 0b982e94305920b602d8c847ea6231bbbc59764e Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Wed, 13 May 2026 09:45:14 +0200 Subject: [PATCH] some improvements --- Gamemodes/FreeForAll.cs | 4 +-- Gamemodes/SoloPVP.cs | 2 +- Modules/CustomNetObject.cs | 19 ---------- Modules/DataFlagRateLimiter.cs | 17 ++++----- .../PlayerGameOptionsSender.cs | 4 +-- Modules/GuessManager.cs | 20 ++++------- Patches/ControlPatch.cs | 7 ++-- Patches/ExceptionSwallowers.cs | 22 ++++++++++++ Patches/GameStartManagerPatch.cs | 3 +- Patches/HudPatch.cs | 18 ---------- Patches/PlayerControlPatch.cs | 4 +-- Roles/Standard/Addons/Common/Spurt.cs | 8 ++--- .../Crewmate/Investigate/FortuneTeller.cs | 3 +- .../Crewmate/Investigate/Inspector.cs | 7 ++-- Roles/Standard/Crewmate/Killing/Judge.cs | 11 +++--- Roles/Standard/Crewmate/Power/Adventurer.cs | 36 ++++++++++--------- Roles/Standard/Crewmate/Power/Alchemist.cs | 6 ++-- Roles/Standard/Crewmate/Power/Swapper.cs | 11 +++--- Roles/Standard/Impostor/Killing/Councillor.cs | 11 +++--- Roles/Standard/Neutral/Benign/RoomRusher.cs | 16 +++++++-- 20 files changed, 103 insertions(+), 126 deletions(-) create mode 100644 Patches/ExceptionSwallowers.cs diff --git a/Gamemodes/FreeForAll.cs b/Gamemodes/FreeForAll.cs index 858457daf..049d5dde7 100644 --- a/Gamemodes/FreeForAll.cs +++ b/Gamemodes/FreeForAll.cs @@ -134,7 +134,7 @@ internal static class FreeForAll FFAShieldedList = []; KillCount = []; - RoundTime = FFAGameTime.GetInt() + 8; + RoundTime = FFAGameTime.GetInt() - 10; Utils.SendRPC(CustomRPC.FFASync, 1, RoundTime); PlayerTeams = []; @@ -375,7 +375,7 @@ internal static class FreeForAll if (!Main.IntroDestroyed || !GameStates.IsInTask || ExileController.Instance || Options.CurrentGameMode != CustomGameMode.FFA || !AmongUsClient.Instance.AmHost) return; long now = Utils.TimeStamp; - if (LastFixedUpdate == now) return; + if (IntroCutsceneDestroyPatch.IntroDestroyTS + 10 > now || LastFixedUpdate == now) return; LastFixedUpdate = now; RoundTime--; diff --git a/Gamemodes/SoloPVP.cs b/Gamemodes/SoloPVP.cs index 1b096f2cf..bfa934664 100644 --- a/Gamemodes/SoloPVP.cs +++ b/Gamemodes/SoloPVP.cs @@ -253,7 +253,7 @@ internal static class SoloPVP { int waitingTime = SoloPVP_ResurrectionWaitingTime.GetInt(); - if (waitingTime <= 1) + if (waitingTime <= 2) { PlayerHP[target.PlayerId] = PlayerHPMax[target.PlayerId]; LastHurt[target.PlayerId] = Utils.TimeStamp; diff --git a/Modules/CustomNetObject.cs b/Modules/CustomNetObject.cs index 12a557a6e..18042c284 100644 --- a/Modules/CustomNetObject.cs +++ b/Modules/CustomNetObject.cs @@ -953,23 +953,4 @@ namespace EHR Active = true; } } -} - -// This method sometimes throws an exception, preventing further code from running -[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RawSetName))] -static class RawSetNameErrorFixPatch -{ - public static Exception Finalizer() - { - return null; - } -} - -[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.SetName))] -static class SetNameErrorFixPatch -{ - public static Exception Finalizer() - { - return null; - } } \ No newline at end of file diff --git a/Modules/DataFlagRateLimiter.cs b/Modules/DataFlagRateLimiter.cs index 40a96656a..9f9bfef14 100644 --- a/Modules/DataFlagRateLimiter.cs +++ b/Modules/DataFlagRateLimiter.cs @@ -22,6 +22,8 @@ public static class DataFlagRateLimiter } } + private static int LastPingMs; + // ========================= // RELIABLE // ========================= @@ -66,11 +68,11 @@ public static class DataFlagRateLimiter switch (channel) { case SendOption.Reliable: - EnqueueInternal(ReliableQueue, ref ReliableSent, ReliableTimer, ReliableRateLimitPerSecond, qa); + EnqueueInternal(ReliableQueue, ref ReliableSent, ReliableRateLimitPerSecond, qa); break; case SendOption.None: // Unreliable - EnqueueInternal(UnreliableQueue, ref UnreliableSent, UnreliableTimer, UnreliableRateLimitPerSecond, qa); + EnqueueInternal(UnreliableQueue, ref UnreliableSent, UnreliableRateLimitPerSecond, qa); break; } @@ -91,17 +93,9 @@ public static class DataFlagRateLimiter private static void EnqueueInternal( Queue queue, ref int sent, - Stopwatch timer, int limit, QueuedAction qa) { - // Reset window every second - if (timer.ElapsedMilliseconds >= 1000) - { - timer.Restart(); - sent = 0; - } - // Try immediate execution if no backlog if (queue.Count == 0 && sent + qa.Cost <= limit) { @@ -120,8 +114,9 @@ public static class DataFlagRateLimiter int limit) { // Reset window every second - if (timer.ElapsedMilliseconds >= 1000) + if (timer.ElapsedMilliseconds >= 1000 + Math.Max(0, LastPingMs - AmongUsClient.Instance.Ping)) { + LastPingMs = AmongUsClient.Instance.Ping; timer.Restart(); sent = 0; } diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs index 480851fcb..fedd01be2 100644 --- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs +++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs @@ -324,9 +324,9 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS foreach (CustomRoles subRole in state.SubRoles) { - if (subRole.IsGhostRole() && subRole != CustomRoles.EvilSpirit) + if (subRole.IsGhostRole()) { - AURoleOptions.GuardianAngelCooldown = GhostRolesManager.AssignedGhostRoles.First(x => x.Value.Role == subRole).Value.Instance.Cooldown; + AURoleOptions.GuardianAngelCooldown = subRole == CustomRoles.EvilSpirit ? Spiritcaller.SpiritAbilityCooldown.GetFloat() : GhostRolesManager.AssignedGhostRoles.Values.First(x => x.Role == subRole).Instance.Cooldown; continue; } diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index 9440bd3cc..8bcb87804 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -36,9 +36,9 @@ public static class GuessManager return Main.EnumeratePlayerControls().Aggregate(GetString("PlayerIdList"), (current, pc) => current + $"\n{pc.PlayerId.ToString()} → {pc.GetRealName()}"); } - public static bool CheckCommand(ref string msg, string command, bool exact, out bool spamRequired) + public static bool CheckCommand(ref string msg, string command, bool exact) { - Utils.CheckServerCommand(ref msg, out spamRequired); + Utils.CheckServerCommand(ref msg, out _); string[] comList = command.Split('|'); @@ -61,7 +61,7 @@ public static class GuessManager return false; } - public static bool GuesserMsg(PlayerControl pc, string msg, bool isUI = false, bool ssMenu = false) + 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; @@ -72,8 +72,8 @@ public static class GuessManager int operate; // 1: ID, 2: Guess msg = msg.ToLower().TrimStart().TrimEnd(); - if (CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true, out bool spamRequired)) operate = 1; - else if (CheckCommand(ref msg, "shoot|guess|bet|st|bt|猜|赌", false, out spamRequired)) operate = 2; + if (CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true)) operate = 1; + else if (CheckCommand(ref msg, "shoot|guess|bet|st|bt|猜|赌", false)) operate = 2; else return false; Logger.Msg(msg, "Msg Guesser"); @@ -119,13 +119,6 @@ public static class GuessManager SkipCheck: - if (!isUI && !ssMenu && spamRequired && (pc.GetCustomRole() is CustomRoles.Decryptor or CustomRoles.NecroGuesser || - pc.Is(CustomRoles.NiceGuesser) || - pc.Is(CustomRoles.EvilGuesser) || - pc.Is(CustomRoles.Doomsayer) || - pc.Is(CustomRoles.Guesser) || Options.GuesserMode.GetBool())) - Utils.SendMessage("\n", pc.PlayerId, GetString("NoSpamAnymoreUseCmd")); - if (!MsgToPlayerAndRole(msg, out byte targetId, out CustomRoles role, out string error)) { ShowMessage(error); @@ -325,6 +318,7 @@ public static class GuessManager case CustomRoles.Ankylosaurus: ShowMessage("GuessAnkylosaurus"); return true; + case CustomRoles.Tree: case CustomRoles.Car: case CustomRoles.DonutDelivery when DonutDelivery.IsUnguessable(pc, target): case CustomRoles.Shifter: @@ -1355,7 +1349,7 @@ public static class GuessManager SelectedRole = Enum.Parse(display, true); } - GuesserMsg(guesserId.GetPlayer(), $"/bt {Target.PlayerId} {GetString(SelectedRole.ToString())}", ssMenu: true); + GuesserMsg(guesserId.GetPlayer(), $"/bt {Target.PlayerId} {GetString(SelectedRole.ToString())}"); Reset(); break; } diff --git a/Patches/ControlPatch.cs b/Patches/ControlPatch.cs index 9eb295892..82863ef97 100644 --- a/Patches/ControlPatch.cs +++ b/Patches/ControlPatch.cs @@ -32,9 +32,10 @@ internal static class ControllerManagerUpdatePatch { if (ClientControlGUI.Instance) { - if (Input.GetKeyDown(KeyCode.Delete) || - KeysDown(KeyCode.LeftControl, KeyCode.BackQuote) || - KeysDown(KeyCode.RightControl, KeyCode.BackQuote)) + if ((!HudManager.InstanceExists || !HudManager.Instance.Chat || !HudManager.Instance.Chat.IsOpenOrOpening) && + (Input.GetKeyDown(KeyCode.Delete) || + KeysDown(KeyCode.LeftControl, KeyCode.BackQuote) || + KeysDown(KeyCode.RightControl, KeyCode.BackQuote))) ClientControlGUI.Instance.IsOpen = !ClientControlGUI.Instance.IsOpen; if (ClientControlGUI.Instance.IsOpen) return; diff --git a/Patches/ExceptionSwallowers.cs b/Patches/ExceptionSwallowers.cs new file mode 100644 index 000000000..36e963643 --- /dev/null +++ b/Patches/ExceptionSwallowers.cs @@ -0,0 +1,22 @@ +using System; +using HarmonyLib; +using InnerNet; + +namespace EHR.Patches; + +// These methods sometimes throw random exceptions in the base game code and stop the code after them from executing +// Simply swallow the exception and continue as if nothing happened + +[HarmonyPatch(typeof(AbilityButton), nameof(AbilityButton.SetFromSettings))] +[HarmonyPatch(typeof(ActionButton), nameof(ActionButton.SetEnabled))] +[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RawSetName))] +[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.SetName))] +[HarmonyPatch(typeof(CosmeticsLayer), nameof(CosmeticsLayer.UpdateBodyMaterial))] +[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.SendOrDisconnect))] +static class ExceptionSwallowers +{ + public static Exception Finalizer() + { + return null; + } +} \ No newline at end of file diff --git a/Patches/GameStartManagerPatch.cs b/Patches/GameStartManagerPatch.cs index 06c3a77c8..fefd5dff6 100644 --- a/Patches/GameStartManagerPatch.cs +++ b/Patches/GameStartManagerPatch.cs @@ -110,8 +110,7 @@ public static class GameStartManagerPatch AURoleOptions.SetOpt(Main.NormalOptions.CastFast()); if (AURoleOptions.ShapeshifterCooldown == 0f) AURoleOptions.ShapeshifterCooldown = Main.LastShapeshifterCooldown.Value; - - //AURoleOptions.GuardianAngelCooldown = Spiritcaller.SpiritAbilityCooldown.GetFloat(); + AURoleOptions.ProtectionDurationSeconds = 0f; } catch (Exception ex) { Logger.Error(ex.ToString(), "GameStartManagerStartPatch.Postfix (1)"); } diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 3d9e5c4c1..725ed9fa4 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -693,24 +693,6 @@ internal static class SetHudActivePatch } } -[HarmonyPatch(typeof(AbilityButton), nameof(AbilityButton.SetFromSettings))] -static class AbilityButtonSetFromSettingsPatch -{ - public static Exception Finalizer() - { - return null; - } -} - -[HarmonyPatch(typeof(ActionButton), nameof(ActionButton.SetEnabled))] -static class ActionButtonSetEnabledPatch -{ - public static Exception Finalizer() - { - return null; - } -} - // From https://github.com/AU-Avengers/TOU-Mira/blob/main/TownOfUs/Patches/HudManagerPatches.cs [HarmonyPatch(typeof(HudManager), nameof(HudManager.Start))] [HarmonyPriority(Priority.Last)] diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index e55b3f040..2dfac225c 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -1697,9 +1697,9 @@ internal static class FixedUpdatePatch if (!GameStates.IsLobby) { - if (player.Is(CustomRoles.Spurt) && !Mathf.Approximately(Main.AllPlayerSpeed[playerId], Spurt.StartingSpeed[playerId]) && !inTask && !GameStates.IsMeeting) // fix ludicrous bug + if (player.Is(CustomRoles.Spurt) && !Mathf.Approximately(Main.AllPlayerSpeed[playerId], Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod)) && !inTask && !GameStates.IsMeeting) // fix ludicrous bug { - Main.AllPlayerSpeed[playerId] = Spurt.StartingSpeed[playerId]; + Main.AllPlayerSpeed[playerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod); player.MarkDirtySettings(); } diff --git a/Roles/Standard/Addons/Common/Spurt.cs b/Roles/Standard/Addons/Common/Spurt.cs index 83c44bc30..7f41086fc 100644 --- a/Roles/Standard/Addons/Common/Spurt.cs +++ b/Roles/Standard/Addons/Common/Spurt.cs @@ -1,5 +1,5 @@ using System.Collections.Generic; -using System.Linq; +using AmongUs.GameOptions; using UnityEngine; using static EHR.Options; @@ -15,7 +15,6 @@ internal class Spurt : IAddon public static bool LocalPlayerAvoidsZeroAndOneHundredPrecent; private static readonly Dictionary LastPos = []; - public static readonly Dictionary StartingSpeed = []; private static readonly Dictionary LastNum = []; private static readonly Dictionary LastUpdate = []; public AddonTypes Type => AddonTypes.Helpful; @@ -43,14 +42,13 @@ internal class Spurt : IAddon public static void Add() { - foreach ((PlayerControl pc, float speed) in Main.EnumerateAlivePlayerControls().Zip(Main.AllPlayerSpeed.Values)) + foreach (PlayerControl pc in Main.EnumerateAlivePlayerControls()) { if (pc.Is(CustomRoles.Spurt)) { LastPos[pc.PlayerId] = pc.Pos(); LastNum[pc.PlayerId] = 0; LastUpdate[pc.PlayerId] = Utils.TimeStamp; - StartingSpeed[pc.PlayerId] = speed; } } @@ -59,7 +57,7 @@ internal class Spurt : IAddon public static void DeathTask(PlayerControl player) { - Main.AllPlayerSpeed[player.PlayerId] = StartingSpeed[player.PlayerId]; + Main.AllPlayerSpeed[player.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod); player.MarkDirtySettings(); } diff --git a/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs b/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs index 2da66a4e6..c20eb2886 100644 --- a/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs +++ b/Roles/Standard/Crewmate/Investigate/FortuneTeller.cs @@ -80,7 +80,8 @@ public class FortuneTeller : RoleBase (List RoleList, PlayerControl Player)[] roleList = Main.CustomRoleValues .Where(x => !x.IsVanilla() && !x.IsAdditionRole() && x is not CustomRoles.GM and not CustomRoles.Convict and not CustomRoles.NotAssigned && !x.IsForOtherGameMode() && !CustomRoleSelector.RoleResult.ContainsValue(x)) - .OrderBy(x => x.IsEnable() ? IRandom.Instance.Next(10) : IRandom.Instance.Next(10, 100)) + .Shuffle() + .OrderByDescending(x => x.IsEnable()) .Take(rolesNeeded) .Chunk(RolesPerCategory - 1) .Zip(players, (array, player) => (RoleList: array.ToList(), Player: player)) diff --git a/Roles/Standard/Crewmate/Investigate/Inspector.cs b/Roles/Standard/Crewmate/Investigate/Inspector.cs index b86777be7..32a65ddbe 100644 --- a/Roles/Standard/Crewmate/Investigate/Inspector.cs +++ b/Roles/Standard/Crewmate/Investigate/Inspector.cs @@ -109,9 +109,9 @@ public class Inspector : RoleBase int operate; // 1:ID 2:Check msg = msg.ToLower().TrimStart().TrimEnd(); - if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true, out bool spamRequired)) + if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true)) operate = 1; - else if (GuessManager.CheckCommand(ref msg, "compare|cp|cmp|比较", false, out spamRequired)) + else if (GuessManager.CheckCommand(ref msg, "compare|cp|cmp|比较", false)) operate = 2; else return false; @@ -129,9 +129,6 @@ public class Inspector : RoleBase break; case 2: { - if (!isUI && spamRequired) - Utils.SendMessage("\n", pc.PlayerId, GetString("NoSpamAnymoreUseCmd")); - if (!MsgToPlayerAndRole(msg, out byte targetId1, out byte targetId2, out string error)) { Utils.SendMessage(error, pc.PlayerId); diff --git a/Roles/Standard/Crewmate/Killing/Judge.cs b/Roles/Standard/Crewmate/Killing/Judge.cs index c5f548e07..92530b7e2 100644 --- a/Roles/Standard/Crewmate/Killing/Judge.cs +++ b/Roles/Standard/Crewmate/Killing/Judge.cs @@ -75,16 +75,16 @@ public class Judge : RoleBase foreach (byte pid in list) MeetingUseLimit[pid] = TrialLimitPerMeeting.GetInt(); } - public static bool TrialMsg(PlayerControl pc, string msg, bool isUI = false, bool sendCmdWarn = true) + public static bool TrialMsg(PlayerControl pc, string msg, bool isUI = false) { if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || !pc || !pc.Is(CustomRoles.Judge)) return false; int operate; // 1:ID 2:Trial msg = msg.ToLower().TrimStart().TrimEnd(); - if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true, out bool spamRequired)) + if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true)) operate = 1; - else if (GuessManager.CheckCommand(ref msg, "jj|tl|trial|审判|判|审", false, out spamRequired)) + else if (GuessManager.CheckCommand(ref msg, "jj|tl|trial|审判|判|审", false)) operate = 2; else return false; @@ -102,9 +102,6 @@ public class Judge : RoleBase break; case 2: { - if (!isUI && spamRequired && sendCmdWarn) - Utils.SendMessage("\n", pc.PlayerId, GetString("NoSpamAnymoreUseCmd")); - if (!MsgToPlayerAndRole(msg, out byte targetId, out string error)) { Utils.SendMessage(error, pc.PlayerId, importance: MessageImportance.Low); @@ -234,7 +231,7 @@ public class Judge : RoleBase public override void OnMeetingShapeshift(PlayerControl shapeshifter, PlayerControl target) { if (Starspawn.IsDayBreak) return; - TrialMsg(shapeshifter, $"/tl {target.PlayerId}", sendCmdWarn: false); + TrialMsg(shapeshifter, $"/tl {target.PlayerId}"); } private static void SendRPC(byte playerId) diff --git a/Roles/Standard/Crewmate/Power/Adventurer.cs b/Roles/Standard/Crewmate/Power/Adventurer.cs index 3c512d6e8..342bae13f 100644 --- a/Roles/Standard/Crewmate/Power/Adventurer.cs +++ b/Roles/Standard/Crewmate/Power/Adventurer.cs @@ -82,7 +82,7 @@ internal class Adventurer : RoleBase private static void HideObject(Resource resource) { - CustomNetObject.AllObjects.FirstOrDefault(x => x is AdventurerItem a && a.Resource == resource)?.Despawn(); + CustomNetObject.AllObjects.Find(x => x is AdventurerItem a && a.Resource == resource)?.Despawn(); } private static OptionItem CreateWeaponEnabledSetting(int id, Weapon weapon) @@ -187,11 +187,11 @@ internal class Adventurer : RoleBase switch (ActiveWeapons[0]) { - case Weapon.Gun when target != null: + case Weapon.Gun when target: pc.RpcCheckAndMurder(target); RemoveAndNotify(); break; - case Weapon.Shield when target != null: + case Weapon.Shield when target: ShieldedPlayers.Add(target.PlayerId); RemoveAndNotify(); break; @@ -279,7 +279,7 @@ internal class Adventurer : RoleBase return; } - if (LastRandomResourceTimeStamp + 20 <= now && pc.PlayerId != AdventurerPC.PlayerId && IRandom.Instance.Next(50) == 0) + if (LastRandomResourceTimeStamp + 20 <= now && pc.PlayerId != AdventurerPC.PlayerId && IRandom.Instance.Next(500) == 0) { if (ResourceLocations.TryGetValue(Resource.Random, out Vector2 location)) { @@ -295,20 +295,24 @@ internal class Adventurer : RoleBase Utils.NotifyRoles(SpecifySeer: AdventurerPC, SpecifyTarget: AdventurerPC); } - if (LastGroupingResourceTimeStamp + 20 <= now && Main.EnumerateAlivePlayerControls().Count(x => x.PlayerId != pc.PlayerId && FastVector2.DistanceWithinRange(x.Pos(), pc.Pos(), 2f)) >= 2) + if (LastGroupingResourceTimeStamp + 20 <= now) { - if (ResourceLocations.TryGetValue(Resource.Grouping, out Vector2 location)) - { - LocateArrow.Remove(AdventurerPC.PlayerId, location); - HideObject(Resource.Grouping); - } - Vector2 pos = pc.Pos(); - LocateArrow.Add(AdventurerPC.PlayerId, pos); - ResourceLocations[Resource.Grouping] = pos; - _ = new AdventurerItem(pos, Resource.Grouping, [AdventurerPC.PlayerId]); - LastGroupingResourceTimeStamp = now; - Utils.NotifyRoles(SpecifySeer: AdventurerPC, SpecifyTarget: AdventurerPC); + + if (Main.EnumerateAlivePlayerControls().Count(x => x.PlayerId != pc.PlayerId && FastVector2.DistanceWithinRange(x.Pos(), pos, 2f)) >= 2) + { + if (ResourceLocations.TryGetValue(Resource.Grouping, out Vector2 location)) + { + LocateArrow.Remove(AdventurerPC.PlayerId, location); + HideObject(Resource.Grouping); + } + + LocateArrow.Add(AdventurerPC.PlayerId, pos); + ResourceLocations[Resource.Grouping] = pos; + _ = new AdventurerItem(pos, Resource.Grouping, [AdventurerPC.PlayerId]); + LastGroupingResourceTimeStamp = now; + Utils.NotifyRoles(SpecifySeer: AdventurerPC, SpecifyTarget: AdventurerPC); + } } } diff --git a/Roles/Standard/Crewmate/Power/Alchemist.cs b/Roles/Standard/Crewmate/Power/Alchemist.cs index 7921123fc..ac23d6a6d 100644 --- a/Roles/Standard/Crewmate/Power/Alchemist.cs +++ b/Roles/Standard/Crewmate/Power/Alchemist.cs @@ -116,6 +116,8 @@ public class Alchemist : RoleBase public override void OnTaskComplete(PlayerControl pc, int completedTaskCount, int totalTaskCount) { + if (!pc.IsAlive()) return; + PotionID = (byte)IRandom.Instance.Next(1, 8); SendRPCData(); @@ -250,7 +252,7 @@ public class Alchemist : RoleBase InvisTimer = new CountdownTimer(invisDuration, () => { InvisTimer = null; - if (pc == null || !pc.IsAlive()) return; + if (!pc || !pc.IsAlive()) return; Main.EnumeratePlayerControls().Without(pc).Do(x => instance.RpcExitVentDesync(ventId, x)); pc.Notify(GetString("SwooperInvisStateOut")); }, onTick: pc.IsModdedClient() ? null : () => pc.Notify(string.Format(GetString("SwooperInvisStateCountdown"), (int)Math.Ceiling(InvisTimer.Remaining.TotalSeconds)), overrideAll: true), onCanceled: () => InvisTimer = null); @@ -308,7 +310,7 @@ public class Alchemist : RoleBase public override string GetProgressText(byte playerId, bool comms) { - if (Utils.GetPlayerById(playerId) == null || !GameStates.IsInTask || playerId.IsPlayerModdedClient()) return base.GetProgressText(playerId, comms); + if (!GameStates.IsInTask || playerId.IsPlayerModdedClient()) return base.GetProgressText(playerId, comms); var sb = new StringBuilder(base.GetProgressText(playerId, comms)); diff --git a/Roles/Standard/Crewmate/Power/Swapper.cs b/Roles/Standard/Crewmate/Power/Swapper.cs index 34cda314f..96e18dfa4 100644 --- a/Roles/Standard/Crewmate/Power/Swapper.cs +++ b/Roles/Standard/Crewmate/Power/Swapper.cs @@ -66,7 +66,7 @@ public class Swapper : RoleBase CNO = null; } - public static bool SwapMsg(PlayerControl pc, string msg, bool isUI = false, bool sendCmdWarn = true) + public static bool SwapMsg(PlayerControl pc, string msg, bool isUI = false) { if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || !pc || pc.GetCustomRole() != CustomRoles.Swapper) return false; @@ -75,9 +75,9 @@ public class Swapper : RoleBase int operate; msg = msg.ToLower().TrimStart().TrimEnd(); - if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true, out bool spamRequired)) + if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true)) operate = 1; - else if (GuessManager.CheckCommand(ref msg, "sw|换票|换|swap|st", false, out spamRequired)) + else if (GuessManager.CheckCommand(ref msg, "sw|换票|换|swap|st", false)) operate = 2; else return false; @@ -104,9 +104,6 @@ public class Swapper : RoleBase return true; } - if (HideMsg.GetBool() && !isUI && spamRequired && sendCmdWarn) - Utils.SendMessage("\n", pc.PlayerId, GetString("NoSpamAnymoreUseCmd")); - if (!byte.TryParse(msg.Replace(" ", string.Empty), out byte targetId)) { Utils.SendMessage(GetString("SwapHelp"), pc.PlayerId); @@ -230,7 +227,7 @@ public class Swapper : RoleBase if (CNO == null) CNO = CanSwapSelf.GetBool() ? new ShapeshiftMenuElement(shapeshifter.PlayerId) : null; else if (CNO.playerControl.NetId == target.NetId) target = shapeshifter; - SwapMsg(shapeshifter, $"/sw {target.PlayerId}", sendCmdWarn: false); + SwapMsg(shapeshifter, $"/sw {target.PlayerId}"); } public override void OnReportDeadBody() diff --git a/Roles/Standard/Impostor/Killing/Councillor.cs b/Roles/Standard/Impostor/Killing/Councillor.cs index 5324c3213..7209a3fd3 100644 --- a/Roles/Standard/Impostor/Killing/Councillor.cs +++ b/Roles/Standard/Impostor/Killing/Councillor.cs @@ -89,16 +89,16 @@ public class Councillor : RoleBase MeetingKillLimit[CouncillorId] = MurderLimitPerMeeting.GetInt(); } - public static bool MurderMsg(PlayerControl pc, string msg, bool isUI = false, bool sendCmdWarn = true) + public static bool MurderMsg(PlayerControl pc, string msg, bool isUI = false) { if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || !pc || !pc.Is(CustomRoles.Councillor)) return false; int operate; // 1:ID 2:Kill msg = msg.ToLower().TrimStart().TrimEnd(); - if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true, out bool spamRequired)) + if (GuessManager.CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id", true)) operate = 1; - else if (GuessManager.CheckCommand(ref msg, "shoot|guess|bet|st|gs|bt|猜|赌|sp|jj|tl|审判|判|审", false, out spamRequired)) + else if (GuessManager.CheckCommand(ref msg, "shoot|guess|bet|st|gs|bt|猜|赌|sp|jj|tl|审判|判|审", false)) operate = 2; else return false; @@ -116,9 +116,6 @@ public class Councillor : RoleBase break; case 2: { - if (!isUI && spamRequired && sendCmdWarn) - Utils.SendMessage("\n", pc.PlayerId, GetString("NoSpamAnymoreUseCmd")); - if (!MsgToPlayerAndRole(msg, out byte targetId, out string error)) { Utils.SendMessage(error, pc.PlayerId); @@ -262,7 +259,7 @@ public class Councillor : RoleBase public override void OnMeetingShapeshift(PlayerControl shapeshifter, PlayerControl target) { if (Starspawn.IsDayBreak) return; - MurderMsg(shapeshifter, $"/tl {target.PlayerId}", sendCmdWarn: false); + MurderMsg(shapeshifter, $"/tl {target.PlayerId}"); } private static void SendRPC(byte playerId) diff --git a/Roles/Standard/Neutral/Benign/RoomRusher.cs b/Roles/Standard/Neutral/Benign/RoomRusher.cs index 5911e3c7a..4176745fe 100644 --- a/Roles/Standard/Neutral/Benign/RoomRusher.cs +++ b/Roles/Standard/Neutral/Benign/RoomRusher.cs @@ -38,7 +38,7 @@ public class RoomRusher : RoleBase public override void SetupCustomOption() { StartSetup(645100) - .AutoSetupOption(ref GlobalTimeAddition, 4, new IntegerValueRule(0, 15, 1), OptionFormat.Seconds, overrideName: "RR_GlobalTimeAddition") + .AutoSetupOption(ref GlobalTimeAddition, 6, new IntegerValueRule(0, 15, 1), OptionFormat.Seconds, overrideName: "RR_GlobalTimeAddition") .AutoSetupOption(ref MaxVents, 1, new IntegerValueRule(0, 30, 1)) .AutoSetupOption(ref RoomNameDisplay, true, overrideName: "RR_DisplayRoomName") .AutoSetupOption(ref Arrow, false, overrideName: "RR_DisplayArrowToRoom") @@ -115,7 +115,16 @@ public class RoomRusher : RoleBase }; if (involvesDecontamination) - time += 2; + { + int decontaminationTime = Options.ChangeDecontaminationTime.GetBool() + ? map == MapNames.Polus + ? Options.DecontaminationTimeOnPolus.GetInt() + Options.DecontaminationDoorOpenTimeOnPolus.GetInt() + : Options.DecontaminationTimeOnMiraHQ.GetInt() + Options.DecontaminationDoorOpenTimeOnMiraHQ.GetInt() + : 6; + + if (SubmergedCompatibility.IsSubmerged()) decontaminationTime = 6; + time += decontaminationTime; + } switch (map) { @@ -131,7 +140,8 @@ public class RoomRusher : RoleBase time += GlobalTimeAddition.GetInt(); if (time < 6) time = 6; - + + TimeLeft = time; Logger.Info($"Goal = from: {Translator.GetString(previous.ToString())} ({previous}), to: {Translator.GetString(RoomGoal.ToString())} ({RoomGoal}) - Time: {TimeLeft} ({map})", "Room Rusher"); LocateArrow.RemoveAllTarget(RoomRusherId); LocateArrow.Add(RoomRusherId, goalPos);