diff --git a/CTA/CustomTeamAssigner/CustomRoles.cs b/CTA/CustomTeamAssigner/CustomRoles.cs index 43f905769..d72134182 100644 --- a/CTA/CustomTeamAssigner/CustomRoles.cs +++ b/CTA/CustomTeamAssigner/CustomRoles.cs @@ -218,7 +218,7 @@ public enum CustomRoles Marshall, Mathematician, Mayor, - SabotageMaster, // Mechanic + Mechanic, Medic, Mediumshiper, Merchant, @@ -372,7 +372,7 @@ public enum CustomRoles Spirit, Spiritcaller, Sprayer, - DarkHide, // Stalker + Stalker, // Stalker Starspawn, Cultist, Sunnyboy, diff --git a/EHR.csproj b/EHR.csproj index 04ad23bf5..54738d0e0 100644 --- a/EHR.csproj +++ b/EHR.csproj @@ -8,7 +8,7 @@ EHR Gurge44 preview - C:\Program Files\Epic Games\AmongUs + D:\SteamLibrary\steamapps\common\Among Us true True $(MSBuildProjectName) diff --git a/Modules/AFKDetector.cs b/Modules/AFKDetector.cs index dbadf588a..ef9218d6b 100644 --- a/Modules/AFKDetector.cs +++ b/Modules/AFKDetector.cs @@ -81,6 +81,7 @@ public static class AFKDetector { Logger.SendInGame(Translator.GetString("AFKTooMany")); PlayerData.Clear(); + Utils.NotifyRoles(ForceLoop: true); } } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index b3a1f0ee0..edf7c7112 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -2797,33 +2797,7 @@ public static class Utils bool shouldSeeTargetAddons = seer.PlayerId == target.PlayerId || new[] { seer, target }.All(x => x.Is(Team.Impostor)); string targetRoleText = - (!seer.IsAlive() && Options.GhostCanSeeOtherRoles.GetBool()) || - (seer.Is(CustomRoles.Mimic) && !target.IsAlive() && Options.MimicCanSeeDeadRoles.GetBool()) || - (target.Is(CustomRoles.Gravestone) && !target.IsAlive()) || - (Main.LoversPlayers.TrueForAll(x => x.PlayerId == seer.PlayerId || x.PlayerId == target.PlayerId) && Main.LoversPlayers.Count == 2 && Lovers.LoverKnowRoles.GetBool()) || - (seer.Is(CustomRoleTypes.Coven) && target.Is(CustomRoleTypes.Coven)) || - (seer.Is(CustomRoleTypes.Impostor) && target.Is(CustomRoleTypes.Impostor) && Options.ImpKnowAlliesRole.GetBool() && CustomTeamManager.ArentInCustomTeam(seer.PlayerId, target.PlayerId)) || - (seer.IsMadmate() && target.Is(CustomRoleTypes.Impostor) && Options.MadmateKnowWhosImp.GetBool()) || - (seer.Is(CustomRoleTypes.Impostor) && target.IsMadmate() && Options.ImpKnowWhosMadmate.GetBool()) || - (seer.Is(CustomRoles.Crewpostor) && target.Is(CustomRoleTypes.Impostor) && Options.CrewpostorKnowsAllies.GetBool()) || - (seer.Is(CustomRoles.Hypocrite) && target.Is(CustomRoleTypes.Impostor) && Hypocrite.KnowsAllies.GetBool()) || - (seer.Is(CustomRoleTypes.Impostor) && target.Is(CustomRoles.Hypocrite) && Hypocrite.AlliesKnowHypocrite.GetBool()) || - (seer.Is(CustomRoleTypes.Impostor) && target.Is(CustomRoles.Crewpostor) && Options.AlliesKnowCrewpostor.GetBool()) || - (seer.IsMadmate() && target.IsMadmate() && Options.MadmateKnowWhosMadmate.GetBool()) || - ((seer.Is(CustomRoles.Sidekick) || seer.Is(CustomRoles.Recruit) || seer.Is(CustomRoles.Jackal)) && (target.Is(CustomRoles.Sidekick) || target.Is(CustomRoles.Recruit) || target.Is(CustomRoles.Jackal))) || - (target.Is(CustomRoles.Workaholic) && Workaholic.WorkaholicVisibleToEveryone.GetBool()) || - (target.Is(CustomRoles.Doctor) && !target.HasEvilAddon() && Options.DoctorVisibleToEveryone.GetBool()) || - (target.Is(CustomRoles.Mayor) && Mayor.MayorRevealWhenDoneTasks.GetBool() && target.GetTaskState().IsTaskFinished) || - (Marshall.CanSeeMarshall(seer) && target.Is(CustomRoles.Marshall) && target.GetTaskState().IsTaskFinished) || - (Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) || - (CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) && CustomTeamManager.IsSettingEnabledForPlayerTeam(seer.PlayerId, CTAOption.KnowRoles)) || - Main.PlayerStates.Values.Any(x => x.Role.KnowRole(seer, target)) || - Markseeker.PlayerIdList.Any(x => Main.PlayerStates[x].Role is Markseeker { IsEnable: true, TargetRevealed: true } ms && ms.MarkedId == target.PlayerId) || - Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun || - (Options.CurrentGameMode == CustomGameMode.HideAndSeek && CustomHnS.IsRoleTextEnabled(seer, target)) || - (seer.IsRevealedPlayer(target) && !target.Is(CustomRoles.Trickster)) || - (seer.Is(CustomRoles.God) && God.KnowInfo.GetValue() == 2) || - target.Is(CustomRoles.GM) + KnowsTargetRole(seer, target) ? $"{target.GetDisplayRoleName(seeTargetBetrayalAddons: shouldSeeTargetAddons)}{GetProgressText(target)}\r\n" : string.Empty; @@ -2942,7 +2916,7 @@ public static class Utils additionalSuffixes.Add(AFKDetector.GetSuffix(seer, target)); if (!forMeeting && Options.CurrentGameMode == CustomGameMode.Standard && Main.Invisible.Contains(target.PlayerId)) - additionalSuffixes.Add(ColorString(Palette.White_75Alpha, GetString("Invisible"))); + additionalSuffixes.Add(ColorString(Palette.White_75Alpha, "\n" + GetString("Invisible"))); TargetSuffix.Append(BuildSuffix(seer, target, meeting: forMeeting)); @@ -3012,6 +2986,37 @@ public static class Utils return hasValue; } + public static bool KnowsTargetRole(PlayerControl seer, PlayerControl target) + { + return (!seer.IsAlive() && Options.GhostCanSeeOtherRoles.GetBool()) || + (seer.Is(CustomRoles.Mimic) && !target.IsAlive() && Options.MimicCanSeeDeadRoles.GetBool()) || + (target.Is(CustomRoles.Gravestone) && !target.IsAlive()) || + (Main.LoversPlayers.TrueForAll(x => x.PlayerId == seer.PlayerId || x.PlayerId == target.PlayerId) && Main.LoversPlayers.Count == 2 && Lovers.LoverKnowRoles.GetBool()) || + (seer.Is(CustomRoleTypes.Coven) && target.Is(CustomRoleTypes.Coven)) || + (seer.Is(CustomRoleTypes.Impostor) && target.Is(CustomRoleTypes.Impostor) && Options.ImpKnowAlliesRole.GetBool() && CustomTeamManager.ArentInCustomTeam(seer.PlayerId, target.PlayerId)) || + (seer.IsMadmate() && target.Is(CustomRoleTypes.Impostor) && Options.MadmateKnowWhosImp.GetBool()) || + (seer.Is(CustomRoleTypes.Impostor) && target.IsMadmate() && Options.ImpKnowWhosMadmate.GetBool()) || + (seer.Is(CustomRoles.Crewpostor) && target.Is(CustomRoleTypes.Impostor) && Options.CrewpostorKnowsAllies.GetBool()) || + (seer.Is(CustomRoles.Hypocrite) && target.Is(CustomRoleTypes.Impostor) && Hypocrite.KnowsAllies.GetBool()) || + (seer.Is(CustomRoleTypes.Impostor) && target.Is(CustomRoles.Hypocrite) && Hypocrite.AlliesKnowHypocrite.GetBool()) || + (seer.Is(CustomRoleTypes.Impostor) && target.Is(CustomRoles.Crewpostor) && Options.AlliesKnowCrewpostor.GetBool()) || + (seer.IsMadmate() && target.IsMadmate() && Options.MadmateKnowWhosMadmate.GetBool()) || + ((seer.Is(CustomRoles.Sidekick) || seer.Is(CustomRoles.Recruit) || seer.Is(CustomRoles.Jackal)) && (target.Is(CustomRoles.Sidekick) || target.Is(CustomRoles.Recruit) || target.Is(CustomRoles.Jackal))) || + (target.Is(CustomRoles.Workaholic) && Workaholic.WorkaholicVisibleToEveryone.GetBool()) || + (target.Is(CustomRoles.Doctor) && !target.HasEvilAddon() && Options.DoctorVisibleToEveryone.GetBool()) || + (target.Is(CustomRoles.Mayor) && Mayor.MayorRevealWhenDoneTasks.GetBool() && target.GetTaskState().IsTaskFinished) || + (Marshall.CanSeeMarshall(seer) && target.Is(CustomRoles.Marshall) && target.GetTaskState().IsTaskFinished) || + (Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Vote && Options.SeeEjectedRolesInMeeting.GetBool()) || + (CustomTeamManager.AreInSameCustomTeam(seer.PlayerId, target.PlayerId) && CustomTeamManager.IsSettingEnabledForPlayerTeam(seer.PlayerId, CTAOption.KnowRoles)) || + Main.PlayerStates.Values.Any(x => x.Role.KnowRole(seer, target)) || + Markseeker.PlayerIdList.Any(x => Main.PlayerStates[x].Role is Markseeker { IsEnable: true, TargetRevealed: true } ms && ms.MarkedId == target.PlayerId) || + Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato or CustomGameMode.Speedrun || + (Options.CurrentGameMode == CustomGameMode.HideAndSeek && CustomHnS.IsRoleTextEnabled(seer, target)) || + (seer.IsRevealedPlayer(target) && !target.Is(CustomRoles.Trickster)) || + (seer.Is(CustomRoles.God) && God.KnowInfo.GetValue() == 2) || + target.Is(CustomRoles.GM); + } + public static void MarkEveryoneDirtySettings() { PlayerGameOptionsSender.SetDirtyToAll(); @@ -3238,6 +3243,8 @@ public static class Utils public static void AddAbilityCD(CustomRoles role, byte playerId, bool includeDuration = true) { + if (Options.UsePhantomBasis.GetBool() && (!role.IsNK() || Options.UsePhantomBasisForNKs.GetBool()) && role.SimpleAbilityTrigger()) return; + if (role.UsesPetInsteadOfKill()) { var kcd = (int)Math.Round(Main.AllPlayerKillCooldown.TryGetValue(playerId, out float killCd) ? killCd : Options.AdjustedDefaultKillCooldown); diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 053426e9a..efe4c7fc1 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -220,6 +220,7 @@ internal static class ChatCommands new(["imitate", "имитировать", "模仿"], "{id}", GetString("CommandDescription.Imitate"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, ImitateCommand, true, true, [GetString("CommandArgs.Imitate.Id")]), new(["retribute", "воздать", "报复"], "{id}", GetString("CommandDescription.Retribute"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, RetributeCommand, true, true, [GetString("CommandArgs.Retribute.Id")]), new(["revive", "воскрешение", "воскрешать", "复活", "reviver"], "{id}", GetString("CommandDescription.Revive"), Command.UsageLevels.Host, Command.UsageTimes.InGame, ReviveCommand, true, false, [GetString("CommandArgs.Revive.Id")]), + new(["select", "выбратьигрока", "选择玩家", "selecionar"], "{id} {role}", GetString("CommandDescription.Select"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, SelectCommand, true, true, [GetString("CommandArgs.Select.Id"), GetString("CommandArgs.Select.Role")]), new(["confirmauth"], "{uuid}", GetString("CommandDescription.ConfirmAuth"), Command.UsageLevels.Everyone, Command.UsageTimes.Always, ConfirmAuthCommand, true, false, [GetString("CommandArgs.ConfirmAuth.UUID")]), diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index 2d7534a03..bd0f4294b 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -661,7 +661,7 @@ internal static class MeetingHudStartPatch { private static void NotifyRoleSkillOnMeetingStart() { - if (!AmongUsClient.Instance.AmHost) return; + if (!AmongUsClient.Instance.AmHost || GameStates.IsEnded) return; List msgToSend = []; diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index a9dbb81bf..e69b0d507 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -1846,7 +1846,7 @@ internal static class FixedUpdatePatch additionalSuffixes.Add(AFKDetector.GetSuffix(seer, target)); if (!GameStates.IsMeeting && Options.CurrentGameMode == CustomGameMode.Standard && Main.Invisible.Contains(target.PlayerId) && (self || (seer.IsImpostor() && target.IsImpostor()))) - additionalSuffixes.Add(ColorString(Palette.White_75Alpha, GetString("Invisible"))); + additionalSuffixes.Add(ColorString(Palette.White_75Alpha, "\n" + GetString("Invisible"))); switch (target.GetCustomRole()) { @@ -2042,7 +2042,7 @@ internal static class FixedUpdatePatch if (Suffix.ToString() != string.Empty) { - offset += moveandstop ? 0.15f : 0.1f; + offset += moveandstop ? 0.15f : 0.2f; offset += moveandstop ? 0f : Suffix.ToString().Count(x => x == '\n') * 0.15f; } diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index 1e87b7a27..343adf784 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -2490,6 +2490,7 @@ "CommandDescription.Retribute": "Guess who killed the player you camped as the Retributionist", "CommandDescription.ConfirmAuth": "Command required to register a new EHR account", "CommandDescription.Revive": "Revives a dead player. Requires special access or No Game End enabled.", + "CommandDescription.Select": "Select your impostor partner and their role.", "CommandArgs.ChangeSetting.Name": "The setting's name to change (leave blank to view all settings)", "CommandArgs.ChangeSetting.UnknownValue": "(leave blank to view what to put here)", "CommandArgs.Rename.Name": "Your new name", @@ -2583,6 +2584,8 @@ "CommandArgs.Retribute.Id": "The potential killer's ID to guess", "CommandArgs.ConfirmAuth.UUID": "The unique token provided by the server", "CommandArgs.Revive.Id": "The dead player's ID to revive", + "CommandArgs.Select.Id": "The player's ID to select as your impostor partner", + "CommandArgs.Select.Role": "The role to select for your impostor partner", "Commands.ChangeSettingHelp": "Arguments:\\n- map (theskeld/mirahq/polus/dlekseht/airship/thefungle/custom)\\n- impostors (number)\\n- players (number)\\n- recommended (on/off)\\n- confirmejects (on/off)\\n- emergencymeetings (number)\\n- anonymousvotes (on/off)\\n- emergencycooldown (number)\\n- discussiontime (number)\\n- votingtime (number)\\n- playerspeed (float)\\n- crewmatevision (float)\\n- impostorvision (float)\\n- killcooldown (float)\\n- killdistance (short/medium/long/custom)\\n- taskbarupdates (always/meetings/never)\\n- visualtasks (on/off)\\n- commontasks (number)\\n- longtasks (number)\\n- shorttasks (number)\\n- scientistcount (number)\\n- scientistchance (number)\\n- vitalsdisplaycooldown (float)\\n- batteryduration (float)\\n- engineercount (number)\\n- engineerchance (number)\\n- ventusecooldown (float)\\n- maxtimeinvents (float)\\n- guardianangelcount (number)\\n- guardianangelchance (number)\\n- protectcooldown (float)\\n- protectduration (float)\\n- protectvisibletoimpostors (on/off)\\n- shapeshiftercount (number)\\n- shapeshifterchance (number)\\n- shapeshiftduration (float)\\n- shapeshiftcooldown (float)\\n- leaveshapeshiftevidence (on/off)\\n- phantomcount (number)\\n- phantomchance (number)\\n- inviscooldown (float)\\n- invisduration (float)\\n- noisemakercount (number)\\n- noisemakerchance (number)\\n- noisemakerimpostoralert (on/off)\\n- noisemakeralertduration (number)\\n- trackercount (number)\\n- trackerchance (number)\\n- trackduration (float)\\n- trackcooldown (float)\\n- trackdelay (float)\\n- ghostdotasks (on/off)\\n\\nNotes:\\n1. Upper and lowercase matters\\n2. Where it says custom, you obviously put a number argument after it\\n3. A float is a single precision floating number, like 1.7\\n4. \"ghostdotasks\" causes issues if you set it\\n5. Example uses:\\n - \"/cs map polus\"\\n - \"/cs killdistance custom 4\"\\n - \"/cs trackdelay 1,7\"\\n - \"/cs confirmejects on\"", "AddTagSuccess": "<#00ffa5>✓ Suceessfully created the tag {0} for {1}. If you want to change it, just use this command again and it will override the current tag. To delete it, simply type <#00a5ff>/deletetag {2}!", "DeleteTagSuccess": "<#00ffa5>✓ Successfully deleted {0}'s tag.", @@ -9007,6 +9010,7 @@ "Postponer": "Postponer", "PostponerInfo": "Postpone Dead Body Spawning", "PostponerInfoLong": "(Impostors):\\nAs the Postponer, when you kill, no dead body spawns instantly. Instead, it will spawn after a delay (in the same place as the murder).", + "Postponer.BodyDelay": "Body Spawm Delay", "Tree": "Tree", "TreeInfo": "You are a Tree", "TreeInfoLong": "(Crewmates):\\nAs a Tree, you can pet to act like one (become anonymous and invisible). After a few seconds, you will fall down, killing or stunning everyone nearby, and making you visible again.", diff --git a/Roles/Crewmate/Captain.cs b/Roles/Crewmate/Captain.cs index 8fea21cc9..2fb31bda1 100644 --- a/Roles/Crewmate/Captain.cs +++ b/Roles/Crewmate/Captain.cs @@ -63,7 +63,7 @@ public class Captain : RoleBase var room = pc.GetPlainShipRoom(); - if (room != null && (TargetRooms.Count == 0 || TargetRooms[^1] != room.RoomId)) + if (room != null && room.RoomId != SystemTypes.Hallway && (TargetRooms.Count == 0 || TargetRooms[^1] != room.RoomId)) TargetRooms.Add(room.RoomId); } @@ -73,7 +73,7 @@ public class Captain : RoleBase LateTask.New(() => { - string msg = string.Format(Translator.GetString("Captain.TargetInfo"), TargetId.ColoredPlayerName(), string.Join(" ➔ ", TargetRooms.ConvertAll(x => Translator.GetString(x.ToString())))); + string msg = string.Format(Translator.GetString("Captain.TargetInfo"), TargetId.ColoredPlayerName(), string.Join(" ➡ ", TargetRooms.ConvertAll(x => Translator.GetString(x.ToString())))); Utils.SendMessage(msg, CaptainId, CustomRoles.Captain.ToColoredString()); TargetRooms = []; }, 10f, "Captain Message"); @@ -110,6 +110,6 @@ public class Captain : RoleBase public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false) { if (seer.PlayerId != CaptainId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting) return string.Empty; - return string.Format(Translator.GetString("Captain.Suffix"), LastNotify); + return string.Format(Translator.GetString("Captain.Suffix"), string.IsNullOrEmpty(LastNotify) ? Translator.GetString("None") : LastNotify); } } \ No newline at end of file diff --git a/Roles/Crewmate/Inquisitor.cs b/Roles/Crewmate/Inquisitor.cs index b37ce6523..5a7e4bc55 100644 --- a/Roles/Crewmate/Inquisitor.cs +++ b/Roles/Crewmate/Inquisitor.cs @@ -43,7 +43,7 @@ public class Inquisitor : RoleBase if (voter == null || target == null || voter.PlayerId == target.PlayerId || Main.DontCancelVoteList.Contains(voter.PlayerId)) return false; PlayerControl[] players = ExcludeDeadPlayers.GetBool() ? Main.AllAlivePlayerControls : Main.AllPlayerControls; - List<(byte Id, CustomRoles Role)> knownRoles = Main.PlayerStates.Values.SelectMany(s => from pc in players where s.Role.KnowRole(target, pc) select (pc.PlayerId, pc.GetCustomRole())).DistinctBy(x => x.PlayerId).ToList(); + List<(byte Id, CustomRoles Role)> knownRoles = [.. from pc in players where Utils.KnowsTargetRole(target, pc) select (pc.PlayerId, pc.GetCustomRole())]; string result; diff --git a/Roles/Crewmate/Tree.cs b/Roles/Crewmate/Tree.cs index 281fe69aa..6d79470b2 100644 --- a/Roles/Crewmate/Tree.cs +++ b/Roles/Crewmate/Tree.cs @@ -25,7 +25,7 @@ public class Tree : RoleBase public override void SetupCustomOption() { StartSetup(655100) - .AutoSetupOption(ref TreeSpriteVisible, true) + .AutoSetupOption(ref TreeSpriteVisible, false) .AutoSetupOption(ref FallDelay, 5, new IntegerValueRule(1, 60, 1), OptionFormat.Seconds) .AutoSetupOption(ref AbilityUseLimit, 1f, new FloatValueRule(0, 20, 0.05f), OptionFormat.Times) .AutoSetupOption(ref AbilityUseGainWithEachTaskCompleted, 0.5f, new FloatValueRule(0f, 5f, 0.05f), OptionFormat.Times) @@ -56,8 +56,14 @@ public class Tree : RoleBase pc.MarkDirtySettings(); bool treeSpriteVisible = TreeSpriteVisible.GetBool(); - if (treeSpriteVisible) TreeSpriteActive = true; - else pc.RpcMakeInvisible(); + + if (treeSpriteVisible) + { + TreeSpriteActive = true; + Utils.NotifyRoles(SpecifyTarget: pc); + } + else + pc.RpcMakeInvisible(); LateTask.New(() => { @@ -66,7 +72,11 @@ public class Tree : RoleBase Main.AllPlayerSpeed[pc.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod); pc.MarkDirtySettings(); - if (treeSpriteVisible) TreeSpriteActive = false; + if (treeSpriteVisible) + { + TreeSpriteActive = false; + Utils.NotifyRoles(SpecifyTarget: pc); + } else pc.RpcMakeVisible(); int chance = FallKillChance.GetInt(); diff --git a/Roles/Impostor/Ambusher.cs b/Roles/Impostor/Ambusher.cs index 88d4fd0a6..0a7ab4e2e 100644 --- a/Roles/Impostor/Ambusher.cs +++ b/Roles/Impostor/Ambusher.cs @@ -117,9 +117,10 @@ public class Ambusher : RoleBase if (!DontCheck) { - var pos = pc.Pos(); - var radius = FollowRadius.GetFloat(); - var closestPlayer = Main.AllAlivePlayerControls.Without(pc).Select(x => (pc: x, distance: Vector2.Distance(x.Pos(), pos))).Where(x => x.distance <= radius).MinBy(x => x.distance).pc; + Vector2 pos = pc.Pos(); + float radius = FollowRadius.GetFloat(); + (PlayerControl pc, float distance)[] nearPlayers = Main.AllAlivePlayerControls.Without(pc).Select(x => (pc: x, distance: Vector2.Distance(x.Pos(), pos))).Where(x => x.distance <= radius).ToArray(); + PlayerControl closestPlayer = nearPlayers.Length == 0 ? null : nearPlayers.MinBy(x => x.distance).pc; if (closestPlayer == null) { @@ -169,11 +170,12 @@ public class Ambusher : RoleBase Count = 0; Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); + if (pc.AmOwner) Utils.DirtyName.Add(pc.PlayerId); } public override void OnGlobalFixedUpdate(PlayerControl pc, bool lowLoad) { - if (!lowLoad && FragilePlayers.TryGetValue(pc.PlayerId, out var endTS) && Utils.TimeStamp >= endTS) + if (!lowLoad && FragilePlayers.TryGetValue(pc.PlayerId, out long endTS) && Utils.TimeStamp >= endTS) FragilePlayers.Remove(pc.PlayerId); } diff --git a/Roles/Impostor/Loner.cs b/Roles/Impostor/Loner.cs index 6369fcb9a..a4f7bb681 100644 --- a/Roles/Impostor/Loner.cs +++ b/Roles/Impostor/Loner.cs @@ -40,6 +40,7 @@ public class Loner : RoleBase PickedPlayer = target.PlayerId; PickedRole = Enum.GetValues().Where(x => x.IsImpostor() && !x.IsVanilla() && !CustomRoleSelector.RoleResult.ContainsValue(x) && x.GetMode() != 0).RandomElement(); + if (PickedRole == CustomRoles.Crewmate) PickedRole = CustomRoles.ImpostorEHR; Utils.SendMessage("\n", shapeshifter.PlayerId, string.Format(Translator.GetString("Loner.Picked"), PickedPlayer.ColoredPlayerName(), PickedRole.ToColoredString())); }