diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aba08ebb4..2175e7944 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -223,7 +223,45 @@ jobs: path: ./EHR*.zip # --------------------------------------------------------- - # 5) Create GitHub Release + # 5) Upload releases to CurseForge + # --------------------------------------------------------- + publish-curseforge: + runs-on: ubuntu-latest + needs: [package] + + steps: + - uses: actions/checkout@v4 + + - name: Download packaged ZIPs + uses: actions/download-artifact@v4 + with: + name: final-zips + path: release-artifacts + + - name: Upload Epic / Microsoft Store build to CurseForge + uses: itsmeow/curseforge-upload@v3 + with: + token: ${{ secrets.CURSEFORGE_API_TOKEN }} + project_id: ${{ secrets.CURSEFORGE_PROJECT_ID }} + game_endpoint: among-us + file_path: release-artifacts/EHR.v${{ github.event.inputs.version }}_Epic-Games_Microsoft-Store.zip + display_name: EHR v${{ github.event.inputs.version }} (x64 - Epic/MS Store) + release_type: release + game_versions: "18.0.0" + + - name: Upload Steam build to CurseForge + uses: itsmeow/curseforge-upload@v3 + with: + token: ${{ secrets.CURSEFORGE_API_TOKEN }} + project_id: ${{ secrets.CURSEFORGE_PROJECT_ID }} + game_endpoint: among-us + file_path: release-artifacts/EHR.v${{ github.event.inputs.version }}_Steam.zip + display_name: EHR v${{ github.event.inputs.version }} (x86 - Steam) + release_type: release + game_versions: "18.0.0" + + # --------------------------------------------------------- + # 6) Create GitHub Release # --------------------------------------------------------- release: runs-on: ubuntu-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index c13f2aa2c..6feb808b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,20 +1,14 @@ # Thank you so much for finding and using EHR! -- New mini game mode under Custom Hide And Seek: `SHIFT AND SEEK` - - This comes with a new seeker role for the game mode called Disguiser, which has a Shapeshifter basis. It has settings to make it behave like an SNS Seeker and customize it however you want. It functions just like any other seeker role in the game mode. - - For convenience, there's a `SHIFT AND SEEK` setting in Mod Settings when the game mode is set to (Custom) Hide And Seek, which makes sure all seeker roles will be Disguiser and enables the role on 100%. Disabling this setting also sets the Disguiser role's spawn chance to 0%. You CAN still use Disguiser even if `SHIFT AND SEEK` is disabled, you just have to re-enable the role yourself. It will spawn like any other seeker role. - - This mini game mode also appears as an option in /gmpoll, which when voted, sets the game mode to (Custom) Hide And Seek, and enables the `SHIFT AND SEEK` setting mentioned above. When normal HNS gets voted, the system disables the setting. -- Fixed kicks after the voting ends on vanilla regions -- Additional optimizations -- Fixed a bug that lead to kicks with large packets -- Fixed kicks caused by chat clearing -- CHNS: Seekers are announced at the start if players can see each other's roles -- First death recording now skips disconnects +- **Fixed host not being able to use judging as ability trigger** +- **Fixed comms preventing judging to trigger abilities** +- Fixed camouflage sometimes not reverting after fixing comms +- Fixed /spectate on others not being reverted properly +- Fixed AOU-EU region being auto-selected at all times on launch -> [!WARNING] -> If you're joining a lobby hosted on vanilla regions (NA/EU/AS), please make sure you have a vanilla region selected in the Create Game menu, otherwise authentication will fail. +[Check the changes from v7.9.0](https://github.com/Gurge44/EndlessHostRoles/releases/tag/v8.0.0) > [!TIP] -> **Play on modded regions** (MEU/MAS/MNA/Niko-EU/Niko-AS/Niko-NA) for an overall better experience. Mobile and PC users can install them [from my website](https://ehr.gurge44.eu/regions). +> **Play on modded regions** (MEU/MAS/MNA/Niko-EU/Niko-AS/Niko-NA/AOU-EU) for an overall better experience. Mobile and PC users can install them [from my website](https://ehr.gurge44.eu/regions). --- \ No newline at end of file diff --git a/CTA/CustomTeamAssigner/CustomRoles.cs b/CTA/CustomTeamAssigner/CustomRoles.cs index fe592aa48..862a5e541 100644 --- a/CTA/CustomTeamAssigner/CustomRoles.cs +++ b/CTA/CustomTeamAssigner/CustomRoles.cs @@ -226,7 +226,6 @@ public enum CustomRoles Inquisitor, Jailor, Journalist, - JudgeOld, LazyGuy, Leery, Lighter, @@ -257,6 +256,7 @@ public enum CustomRoles Perceiver, PortalMaker, President, + Prosecutor, Psychic, Rabbit, Randomizer, diff --git a/CustomRoles.cs b/CustomRoles.cs index fe592aa48..862a5e541 100644 --- a/CustomRoles.cs +++ b/CustomRoles.cs @@ -226,7 +226,6 @@ public enum CustomRoles Inquisitor, Jailor, Journalist, - JudgeOld, LazyGuy, Leery, Lighter, @@ -257,6 +256,7 @@ public enum CustomRoles Perceiver, PortalMaker, President, + Prosecutor, Psychic, Rabbit, Randomizer, diff --git a/Gamemodes/DoomTag.cs b/Gamemodes/DoomTag.cs index 072fb741f..0fbb63367 100644 --- a/Gamemodes/DoomTag.cs +++ b/Gamemodes/DoomTag.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using AmongUs.GameOptions; using EHR.Modules; using Hazel; @@ -11,19 +12,20 @@ namespace EHR.Gamemodes; internal static class DoomTag { private static Dictionary TargetMap = []; - private static Dictionary LowerVisionList = []; + private static HashSet LowerVisionList = []; private static bool FrenzyMode; private static float DefaultSpeed; public static OptionItem BaseKillCooldown; private static OptionItem PunishmentMode; private static OptionItem LowerVisionMultiplier; + private static OptionItem FreezeDuration; private static OptionItem FrenzyPlayerCount; private static OptionItem FrenzyKillCooldown; private static OptionItem FrenzySpeedMultiplier; private static OptionItem ShowTargetArrow; - private static readonly string[] PunishmentModeOptions = ["DoomTag.PunishSuicide", "DoomTag.PunishLowerVision"]; + private static readonly string[] PunishmentModeOptions = ["DoomTag.PunishSuicide", "DoomTag.PunishLowerVision", "DoomTag.PunishFreeze"]; public static void SetupCustomOption() { @@ -40,14 +42,26 @@ internal static class DoomTag PunishmentMode = new StringOptionItem(id++, "DoomTag.PunishmentMode", PunishmentModeOptions, 0, tab) .SetGameMode(gameMode) - .SetColor(color); + .SetColor(color) + .RegisterUpdateValueEvent((_, _, newValue) => + { + LowerVisionMultiplier.SetHidden(newValue != 1); + FreezeDuration.SetHidden(newValue != 2); + }) + .SetRunEventOnLoad(true); - LowerVisionMultiplier = new FloatOptionItem(id++, "DoomTag.LowerVisionMultiplier", new(0f, 10f, 0.5f), 0.5f, tab) + LowerVisionMultiplier = new FloatOptionItem(id++, "DoomTag.LowerVisionMultiplier", new(0f, 10f, 0.5f), 0.25f, tab) .SetParent(PunishmentMode) .SetGameMode(gameMode) .SetColor(color) .SetValueFormat(OptionFormat.Multiplier); + FreezeDuration = new FloatOptionItem(id++, "DoomTag.FreezeDuration", new(0f, 120f, 0.5f), 10f, tab) + .SetParent(PunishmentMode) + .SetGameMode(gameMode) + .SetColor(color) + .SetValueFormat(OptionFormat.Seconds); + FrenzyPlayerCount = new IntegerOptionItem(id++, "DoomTag.FrenzyPlayerCount", new(1, 127, 1), 3, tab) .SetGameMode(gameMode) .SetColor(color) @@ -94,11 +108,11 @@ internal static class DoomTag TargetMap = []; - var allPlayers = Main.CachedAlivePlayerControls(); - if (Main.GM.Value) allPlayers.Remove(PlayerControl.LocalPlayer); - allPlayers.RemoveAll(x => ChatCommands.Spectators.Contains(x.PlayerId)); + var allPlayers = Main.EnumerateAlivePlayerControls(); + if (Main.GM.Value) allPlayers = allPlayers.Without(PlayerControl.LocalPlayer); + allPlayers = allPlayers.Where(x => !ChatCommands.Spectators.Contains(x.PlayerId)); - List playerIds = allPlayers.ConvertAll(x => x.PlayerId).Shuffle(); + List playerIds = allPlayers.Select(x => x.PlayerId).Shuffle(); if (playerIds.Count < 2) { @@ -115,7 +129,7 @@ internal static class DoomTag TargetMap.Remove(TargetMap.GetKeyByValue(targetId)); TargetMap[hunterId] = targetId; if (ShowTargetArrow.GetBool()) TargetArrow.Add(hunterId, targetId); - Logger.Info($"{hunterId.ColoredPlayerName()} 2 targets 2 {targetId.ColoredPlayerName()}", "DoomTag"); + Logger.Info($"{Main.AllPlayerNames.GetValueOrDefault(hunterId, string.Empty)} targets {Main.AllPlayerNames.GetValueOrDefault(targetId, string.Empty)}", "DoomTag"); } SyncTargetMapRPC(); @@ -151,7 +165,7 @@ internal static class DoomTag TargetMap.Remove(TargetMap.GetKeyByValue(nextTarget)); TargetMap[killerId] = nextTarget; if (ShowTargetArrow.GetBool()) TargetArrow.Add(killerId, nextTarget); - Logger.Info($"{killer.GetRealName()}'s new target is {nextTarget.ColoredPlayerName()}", "DoomTag"); + Logger.Info($"{killer.GetRealName()}'s new target is {Main.AllPlayerNames.GetValueOrDefault(nextTarget, string.Empty)}", "DoomTag"); } else { @@ -171,7 +185,7 @@ internal static class DoomTag } else { - Logger.Info($"{killer.GetRealName()} killed wrong target {target.GetRealName()} (expected: {expectedTarget.ColoredPlayerName()})", "DoomTag"); + Logger.Info($"{killer.GetRealName()} killed wrong target {target.GetRealName()} (expected: {Main.AllPlayerNames.GetValueOrDefault(expectedTarget, string.Empty)})", "DoomTag"); if (PunishmentMode.GetInt() == 0) killer.Kill(target); @@ -206,42 +220,59 @@ internal static class DoomTag case 1: float visionMultiplier = LowerVisionMultiplier.GetFloat(); - LowerVisionList[killer.PlayerId] = Utils.TimeStamp; + LowerVisionList.Add(killer.PlayerId); killer.MarkDirtySettings(); killer.Notify(string.Format(GetString("DoomTag.WrongKillLowerVision"), visionMultiplier)); break; + + case 2: + Main.AllPlayerSpeed[killer.PlayerId] = Main.MinSpeed; + killer.MarkDirtySettings(); + float time = FreezeDuration.GetFloat(); + killer.Notify(GetString("DoomTag.WrongKillFreeze"), time - 1f); + LateTask.New(() => + { + if (!killer || !killer.IsAlive() || GameStates.IsEnded) return; + Main.AllPlayerSpeed[killer.PlayerId] = DefaultSpeed; + killer.MarkDirtySettings(); + }, time); + break; } } private static void HandleDeadPlayer(byte deadPlayerId) { if (!AmongUsClient.Instance.AmHost) return; - if (!TargetMap.Remove(deadPlayerId)) return; byte hunterId = TargetMap.GetKeyByValue(deadPlayerId, byte.MaxValue); byte nextTarget = GetTarget(deadPlayerId); + TargetMap.Remove(deadPlayerId); + TargetArrow.RemoveAllTarget(deadPlayerId); LowerVisionList.Remove(deadPlayerId); - if (hunterId != byte.MaxValue && nextTarget != byte.MaxValue && nextTarget != hunterId) + if (hunterId != byte.MaxValue) { TargetArrow.RemoveAllTarget(hunterId); - if (TargetMap.ContainsValue(nextTarget)) - TargetMap.Remove(TargetMap.GetKeyByValue(nextTarget)); - TargetMap[hunterId] = nextTarget; - if (ShowTargetArrow.GetBool()) TargetArrow.Add(hunterId, nextTarget); - LateTask.New(() => + if (nextTarget != byte.MaxValue && nextTarget != hunterId && Main.PlayerStates.TryGetValue(nextTarget, out var state) && !state.IsDead) { - PlayerControl hunter = Utils.GetPlayerById(hunterId); - if (hunter) Utils.NotifyRoles(SpecifySeer: hunter, SpecifyTarget: hunter); - }, 0.3f); - } - else if (hunterId != byte.MaxValue) - { - TargetMap.Remove(hunterId); - TargetArrow.RemoveAllTarget(hunterId); + if (TargetMap.ContainsValue(nextTarget)) + TargetMap.Remove(TargetMap.GetKeyByValue(nextTarget)); + TargetMap[hunterId] = nextTarget; + if (ShowTargetArrow.GetBool()) TargetArrow.Add(hunterId, nextTarget); + + LateTask.New(() => + { + PlayerControl hunter = Utils.GetPlayerById(hunterId); + if (hunter) Utils.NotifyRoles(SpecifySeer: hunter, SpecifyTarget: hunter); + }, 0.3f); + } + else + { + TargetMap.Remove(hunterId); + } } CheckFrenzyMode(); @@ -370,7 +401,7 @@ internal static class DoomTag try { AURoleOptions.GuardianAngelCooldown = 900f; } catch (Exception e) { Utils.ThrowException(e); } - if (LowerVisionList.ContainsKey(playerId)) + if (LowerVisionList.Contains(playerId)) { float vision = LowerVisionMultiplier.GetFloat(); opt.SetVision(false); diff --git a/Gamemodes/SoloPVP.cs b/Gamemodes/SoloPVP.cs index bf780624f..9f2ba3c86 100644 --- a/Gamemodes/SoloPVP.cs +++ b/Gamemodes/SoloPVP.cs @@ -110,19 +110,22 @@ internal static class SoloPVP }, 3f); Utils.SendRPC(CustomRPC.SoloPVPSync, 1); - foreach (PlayerControl pc in Main.CachedAlivePlayerControls()) + foreach (PlayerControl pc in Main.EnumeratePlayerControls()) { - PlayerHPMax.TryAdd(pc.PlayerId, SoloPVP_HPMax.GetFloat()); - PlayerHP.TryAdd(pc.PlayerId, SoloPVP_HPMax.GetFloat()); - PlayerHPReco.TryAdd(pc.PlayerId, SoloPVP_RecoverPerSecond.GetFloat()); - PlayerATK.TryAdd(pc.PlayerId, SoloPVP_ATK.GetFloat()); - PlayerDF.TryAdd(pc.PlayerId, 0f); - - PlayerScore.TryAdd(pc.PlayerId, 0); - Utils.SendRPC(CustomRPC.SoloPVPSync, 2, pc.PlayerId, 0); - - LastHurt.TryAdd(pc.PlayerId, Utils.TimeStamp); - LastCountdownTime.TryAdd(pc.PlayerId, Utils.TimeStamp); + try + { + PlayerHPMax.TryAdd(pc.PlayerId, SoloPVP_HPMax.GetFloat()); + PlayerHP.TryAdd(pc.PlayerId, SoloPVP_HPMax.GetFloat()); + PlayerHPReco.TryAdd(pc.PlayerId, SoloPVP_RecoverPerSecond.GetFloat()); + PlayerATK.TryAdd(pc.PlayerId, SoloPVP_ATK.GetFloat()); + PlayerDF.TryAdd(pc.PlayerId, 0f); + PlayerScore.TryAdd(pc.PlayerId, 0); + LastHurt.TryAdd(pc.PlayerId, Utils.TimeStamp); + LastCountdownTime.TryAdd(pc.PlayerId, Utils.TimeStamp); + + Utils.SendRPC(CustomRPC.SoloPVPSync, 2, pc.PlayerId, 0); + } + catch (Exception e) { Utils.ThrowException(e); } } } @@ -342,7 +345,7 @@ internal static class SoloPVP if (!GameStates.IsInTask || ExileController.Instance || !Main.IntroDestroyed || Options.CurrentGameMode != CustomGameMode.SoloPVP || !AmongUsClient.Instance.AmHost || id >= 254) return; long now = Utils.TimeStamp; - if (LastCountdownTime[id] == now) return; + if (!LastCountdownTime.TryGetValue(id, out long ts) || ts == now) return; LastCountdownTime[id] = now; if (LastHurt[id] + SoloPVP_RecoverAfterSecond.GetInt() < now && PlayerHP[id] < PlayerHPMax[id] && __instance.SoloAlive() && !__instance.inVent) diff --git a/Main.cs b/Main.cs index 75e900d74..4f227f103 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.1"; - public const string PluginDisplayVersion = "7.9.1 Test 1"; - public const bool TestBuild = true; + public const string PluginVersion = "8.0.1"; + public const string PluginDisplayVersion = "8.0.1"; + public const int TestBuildNumber = 0; // 0 = Release public const string NeutralColor = "#ffab1b"; public const string ImpostorColor = "#ff1919"; @@ -581,7 +581,7 @@ public class Main : BasePlugin { CustomRoles.Medic, "#00ff97" }, { CustomRoles.FortuneTeller, "#882c83" }, { CustomRoles.Glitch, "#39FF14" }, - { CustomRoles.JudgeOld, "#f8d85a" }, + { CustomRoles.Prosecutor, "#f8d85a" }, { CustomRoles.Mortician, "#333c49" }, { CustomRoles.Medium, "#a200ff" }, { CustomRoles.Observer, "#a8e0fa" }, @@ -931,6 +931,7 @@ public class Main : BasePlugin BanManager.Init(); TemplateManager.Init(); SpamManager.Init(); + AmciRegistration.Apply(); IRandom.SetInstance(new NetRandomWrapper()); @@ -1005,6 +1006,9 @@ public class Main : BasePlugin try { SubmergedCompatibility.Initialize(); } catch (Exception e) { Utils.ThrowException(e); } + try { LevelImposterCompatibility.Init(); } + catch (Exception e) { Utils.ThrowException(e); } + try { HandleRoleColorFiles(); } catch (Exception e) { Utils.ThrowException(e); } @@ -1012,7 +1016,7 @@ public class Main : BasePlugin Modules.AutoHaunt.Start(); Logger.Msg("========= EHR loaded! =========", "Plugin Load"); - Logger.Msg($"EHR Version: {PluginVersion}, Test Build: {TestBuild}", "Plugin Load"); + Logger.Msg($"EHR Version: {PluginVersion}, Test Build Number: {TestBuildNumber}", "Plugin Load"); }; try diff --git a/Modules/AmciRegistration.cs b/Modules/AmciRegistration.cs new file mode 100644 index 000000000..b987e5033 --- /dev/null +++ b/Modules/AmciRegistration.cs @@ -0,0 +1,52 @@ +using HarmonyLib; + +namespace EHR.Modules; + +/// +/// Handles AU MCI (Among Us Modded Client Identification) registration for EHR. +/// See: https://github.com/Innersloth-LLC/AmongUsModdingInformation +/// +/// On startup, EHR's GUID is written into the game's mod registration slot. +/// The matchmaker picks this up automatically and injects a mod filter into +/// every lobby search, so Find Game exclusively returns EHR lobbies to EHR clients. +/// +/// The hosting side is handled by , which appends +/// EHR's GUID to the host packet so Innersloth's servers register the lobby +/// as modded and remove it from the vanilla matchmaking pool. +/// +public static class AmciRegistration +{ + /// + /// EHR's AMCI mod GUID. Do not change this after it ships to players or they won't be able + /// to find EHR lobbies until they update. + /// + private const string ModGuidString = "446420cc-ce35-4c2f-8f5d-b14f84354421"; + + /// + /// Writes EHR's GUID into the game's mod registration slot so the matchmaker + /// can filter lobby searches to EHR lobbies only. + /// Call once from . + /// The base game code does the rest. + /// + public static void Apply() + { + CurrentModRegistration.ModRegistrationGuidString = ModGuidString; + Logger.Info($"AMCI mod GUID registered: {ModGuidString}", nameof(AmciRegistration)); + } + + // Fixes not being able to host local games when the mod GUID is registered + [HarmonyPatch(typeof(CurrentModRegistration), nameof(CurrentModRegistration.TryGetModRegistrationGuid))] + public static class TryGetModRegistrationGuidPatch + { + public static bool Prefix(ref bool __result) + { + if (GameStates.IsLocalGame) + { + __result = false; + return false; + } + + return true; + } + } +} diff --git a/Modules/Camouflage.cs b/Modules/Camouflage.cs index 174ffb88e..bcb5a8f61 100644 --- a/Modules/Camouflage.cs +++ b/Modules/Camouflage.cs @@ -209,7 +209,7 @@ public static class Camouflage } // if the current Outfit is the same, return - if (newOutfit.Compare(target.Data.DefaultOutfit)) + if (IsCamouflage && newOutfit.Compare(target.Data.DefaultOutfit)) { Logger.Info("Outfit is the same, returning", "Camouflage.RpcSetSkin"); return; diff --git a/Modules/CustomRoleSelector.cs b/Modules/CustomRoleSelector.cs index 3d8fc4414..4103740fc 100644 --- a/Modules/CustomRoleSelector.cs +++ b/Modules/CustomRoleSelector.cs @@ -108,8 +108,6 @@ internal static class CustomRoleSelector switch (role) { - case CustomRoles.Bargainer when Main.LIMap: - case CustomRoles.AntiAdminer when Main.LIMap: case CustomRoles.CameraMan when Main.LIMap: case CustomRoles.Weatherman when Main.LIMap || GameStates.CurrentServerType == GameStates.ServerType.Vanilla: case CustomRoles.Doctor when Options.EveryoneSeesDeathReasons.GetBool(): diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index 8e3ccaa31..192a17aaf 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.JudgeOld => CustomRoles.Crewmate, + CustomRoles.Prosecutor => CustomRoles.Crewmate, CustomRoles.Councillor => CustomRoles.Impostor, CustomRoles.Mortician => CustomRoles.Crewmate, CustomRoles.Medium => CustomRoles.Crewmate, @@ -922,6 +922,13 @@ internal static class CustomRolesHelper return type.GetMethod("OnMeetingShapeshift")?.DeclaringType == type; } + public bool UsesJudgeAbilityAsTrigger() + { + if (!Options.UseJudgeAbilityAsTrigger.GetBool()) return false; + Type type = role.GetRoleClass().GetType(); + return type.GetMethod("OnJudge")?.DeclaringType == type; + } + public bool PetActivatedAbility() { if (Options.CurrentGameMode == CustomGameMode.CaptureTheFlag) return true; @@ -1485,7 +1492,7 @@ internal static class CustomRolesHelper CustomRoles.Ventguard => RoleOptionType.Crewmate_Support, CustomRoles.Wizard => RoleOptionType.Crewmate_Support, CustomRoles.Drainer => RoleOptionType.Crewmate_Killing, - CustomRoles.JudgeOld => RoleOptionType.Crewmate_Killing, + CustomRoles.Prosecutor => RoleOptionType.Crewmate_Killing, CustomRoles.NiceGuesser => RoleOptionType.Crewmate_Killing, CustomRoles.Retributionist => RoleOptionType.Crewmate_Killing, CustomRoles.Sentinel => RoleOptionType.Crewmate_Killing, @@ -1947,7 +1954,7 @@ internal static class CustomRolesHelper CustomRoles.Rascal when !pc.IsCrewmate() => false, CustomRoles.LazyGuy when pc.GetCustomRole().IsAdditionRole() => false, CustomRoles.Stealer when pc.Is(CustomRoles.Vindicator) => false, - CustomRoles.Priority when Main.PlayerStates[pc.PlayerId].Role is not CovenBase coven || coven.CanNeverGetNecronomicon => false, + CustomRoles.Priority when !Main.PlayerStates.TryGetValue(pc.PlayerId, out PlayerState state) || state.Role is not CovenBase coven || coven.CanNeverGetNecronomicon => false, CustomRoles.Bloodlust when !pc.GetCustomRole().IsCrewmate() || pc.GetCustomRole().IsTaskBasedCrewmate() || pc.GetCustomRole() is CustomRoles.Medic => false, CustomRoles.Mare when pc.GetCustomRole() is CustomRoles.Inhibitor or CustomRoles.Saboteur or CustomRoles.Swift or CustomRoles.Nemesis or CustomRoles.Sniper or CustomRoles.Fireworker or CustomRoles.Swooper or CustomRoles.Vampire => false, CustomRoles.Torch when pc.GetCustomRole() is CustomRoles.Lighter or CustomRoles.Ignitor or CustomRoles.Investigator or CustomRoles.Eclipse or CustomRoles.Decryptor => false, diff --git a/Modules/CustomRpcSender.cs b/Modules/CustomRpcSender.cs index 889d2063a..72240786d 100644 --- a/Modules/CustomRpcSender.cs +++ b/Modules/CustomRpcSender.cs @@ -875,6 +875,7 @@ public static class CustomRpcSenderExtensions public bool RpcExiled(PlayerControl target, bool autoStartRpc = true, int targetClientId = -1, bool exileForHost = true) { + if (!AmongUsClient.Instance.AmHost) return false; if (exileForHost) target.Exiled(); if (autoStartRpc) sender.AutoStartRpc(target.NetId, RpcCalls.Exiled, targetClientId).EndRpc(); else sender.StartRpc(target.NetId, RpcCalls.Exiled).EndRpc(); @@ -883,6 +884,7 @@ public static class CustomRpcSenderExtensions public bool RpcExileV2(PlayerControl target, bool autoStartRpc = true, int targetClientId = -1, bool exileForHost = true) { + if (!AmongUsClient.Instance.AmHost) return false; sender.RpcExiled(target, autoStartRpc, targetClientId, exileForHost); FixedUpdatePatch.LoversSuicide(target.PlayerId); return true; diff --git a/Modules/Debugger.cs b/Modules/Debugger.cs index cb1adbc8c..2978972e9 100644 --- a/Modules/Debugger.cs +++ b/Modules/Debugger.cs @@ -204,12 +204,12 @@ public class CustomLogger