diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index 9cf33fa89..631910a53 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -352,7 +352,7 @@ internal static class ExtendedPlayerControl } // If you use vanilla RpcSetRole, it will block further SetRole calls until the next game starts. - private static void RpcSetRoleGlobal(this PlayerControl player, RoleTypes roleTypes) + public static void RpcSetRoleGlobal(this PlayerControl player, RoleTypes roleTypes) { if (AmongUsClient.Instance.AmClient) player.StartCoroutine(player.CoSetRole(roleTypes, true)); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(player.NetId, (byte)RpcCalls.SetRole, SendOption.Reliable); diff --git a/Modules/FixedUpdateCaller.cs b/Modules/FixedUpdateCaller.cs index 95f68cd83..8baa9364e 100644 --- a/Modules/FixedUpdateCaller.cs +++ b/Modules/FixedUpdateCaller.cs @@ -14,6 +14,8 @@ public static class FixedUpdateCaller { private static int NonLowLoadPlayerIndex; + private static long LastFileLoadTS; + // ReSharper disable once UnusedMember.Global public static void Postfix() { @@ -38,6 +40,14 @@ public static class FixedUpdateCaller { LobbyFixedUpdatePatch.Postfix(); LobbyBehaviourUpdatePatch.Postfix(lobbyBehaviour); + + long now = Utils.TimeStamp; + + if (now - LastFileLoadTS > 10) + { + LastFileLoadTS = now; + Options.LoadUserData(); + } } HudManager hudManager = FastDestroyableSingleton.Instance; diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index fdd867a2b..97c420e1e 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -983,7 +983,19 @@ internal static class MeetingHudStartPatch LateTask.New(() => { if (!MeetingHud.Instance || MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding) return; - Main.AllAlivePlayerControls.DoIf(x => x.UsesMeetingShapeshift(), x => x.RpcSetRoleDesync(RoleTypes.Shapeshifter, x.OwnerId)); + + PlayerControl[] aapc = Main.AllAlivePlayerControls; + + foreach (PlayerControl pc in aapc) + { + if (pc.UsesMeetingShapeshift()) + { + var sender = CustomRpcSender.Create($"RpcSetRoleDesync for meeting shapeshift ({Main.AllPlayerNames.GetValueOrDefault(pc.PlayerId, "Someone")})", SendOption.Reliable); + sender.RpcSetRole(pc, RoleTypes.Shapeshifter, pc.OwnerId); + aapc.DoIf(x => x.IsImpostor(), x => sender.RpcSetRole(x, RoleTypes.Crewmate, pc.OwnerId)); + sender.SendMessage(); + } + } }, 8f, "Set Shapeshifter Role For Meeting Use"); } } @@ -1254,7 +1266,11 @@ internal static class MeetingHudOnDestroyPatch Main.LastVotedPlayerInfo = null; if (meetingSS && !AntiBlackout.SkipTasks) - Main.AllAlivePlayerControls.DoIf(x => x.UsesMeetingShapeshift(), x => x.RpcSetRoleDesync(x.GetRoleTypes(), x.OwnerId)); + { + PlayerControl[] aapc = Main.AllAlivePlayerControls; + aapc.DoIf(x => x.UsesMeetingShapeshift(), x => x.RpcSetRoleDesync(x.GetRoleTypes(), x.OwnerId)); + aapc.DoIf(x => x.IsImpostor(), x => x.RpcSetRoleGlobal(x.GetRoleTypes())); + } } } } diff --git a/Patches/OnGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs index 2d9927c57..83a1666ab 100644 --- a/Patches/OnGameStartedPatch.cs +++ b/Patches/OnGameStartedPatch.cs @@ -281,6 +281,7 @@ internal static class ChangeRoleSettings Main.IntroDestroyed = false; ShipStatusBeginPatch.RolesIsAssigned = false; GameEndChecker.Ended = false; + ReportDeadBodyPatch.MeetingStarted = false; HudSpritePatch.ResetButtonIcons = true; diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index c08dbca75..5ebe8f789 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -1194,6 +1194,7 @@ internal static class ReportDeadBodyPatch if (MeetingStarted) return; MeetingStarted = true; + LateTask.New(() => MeetingStarted = false, 1f, "ResetMeetingStarted"); CustomNetObject.OnMeeting(); diff --git a/Roles/AddOns/Common/Deadlined.cs b/Roles/AddOns/Common/Deadlined.cs index 74188720f..26f95d6fb 100644 --- a/Roles/AddOns/Common/Deadlined.cs +++ b/Roles/AddOns/Common/Deadlined.cs @@ -32,7 +32,8 @@ public class Deadlined : IAddon foreach (PlayerControl pc in Main.AllPlayerControls) { TaskState ts = pc.GetTaskState(); - if (pc.Is(CustomRoles.Deadlined) && (!pc.IsAlive() || ts.IsTaskFinished || (!ts.HasTasks && !pc.CanUseKillButton()))) Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Deadlined); + if (pc.Is(CustomRoles.Deadlined) && (!pc.IsAlive() || ts.IsTaskFinished || (!ts.HasTasks && !pc.CanUseKillButton()))) + Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Deadlined); } } diff --git a/Roles/Neutral/Romantic.cs b/Roles/Neutral/Romantic.cs index f10d15c47..454527eb0 100644 --- a/Roles/Neutral/Romantic.cs +++ b/Roles/Neutral/Romantic.cs @@ -4,8 +4,6 @@ using AmongUs.GameOptions; using EHR.Modules; using Hazel; using UnityEngine; -using static EHR.Options; -using static EHR.Translator; namespace EHR.Neutral; @@ -50,54 +48,54 @@ public class Romantic : RoleBase public override void SetupCustomOption() { - SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Romantic); + Options.SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Romantic); BetCooldown = new FloatOptionItem(Id + 10, "RomanticBetCooldown", new(0f, 60f, 1f), 7f, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]) + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]) .SetValueFormat(OptionFormat.Seconds); ProtectCooldown = new FloatOptionItem(Id + 11, "RomanticProtectCooldown", new(0f, 60f, 0.5f), 25f, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]) + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]) .SetValueFormat(OptionFormat.Seconds); ProtectDuration = new FloatOptionItem(Id + 12, "RomanticProtectDuration", new(0f, 60f, 0.5f), 10f, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]) + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]) .SetValueFormat(OptionFormat.Seconds); KnowTargetRole = new BooleanOptionItem(Id + 13, "RomanticKnowTargetRole", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); BetTargetKnowRomantic = new BooleanOptionItem(Id + 14, "RomanticBetTargetKnowRomantic", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); RomanticGetsPartnerConvertedAddons = new BooleanOptionItem(Id + 15, "RomanticGetsPartnerConvertedAddons", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); Arrows = new BooleanOptionItem(Id + 16, "RomanticArrows", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); PartnerHasArrows = new BooleanOptionItem(Id + 17, "RomanticPartnerHasArrows", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); VengefulKCD = new FloatOptionItem(Id + 18, "VengefulKCD", new(0f, 60f, 0.5f), 22.5f, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]) + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]) .SetValueFormat(OptionFormat.Seconds); VengefulCanVent = new BooleanOptionItem(Id + 19, "VengefulCanVent", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); VengefulHasImpVision = new BooleanOptionItem(Id + 20, "VengefulHasImpVision", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); RuthlessKCD = new FloatOptionItem(Id + 21, "RuthlessKCD", new(0f, 60f, 0.5f), 22.5f, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]) + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]) .SetValueFormat(OptionFormat.Seconds); RuthlessCanVent = new BooleanOptionItem(Id + 22, "RuthlessCanVent", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); RuthlessHasImpVision = new BooleanOptionItem(Id + 23, "RuthlessHasImpVision", true, TabGroup.NeutralRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Romantic]); + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Romantic]); } public override void Init() @@ -169,8 +167,8 @@ public class Romantic : RoleBase RomanticPC.SetKillCooldown(); RomanticPC.RPCPlayCustomSound("Bet"); - RomanticPC.Notify(GetString("RomanticBetPlayer")); - if (BetTargetKnowRomantic.GetBool()) target.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Romantic), GetString("RomanticBetOnYou"))); + RomanticPC.Notify(Translator.GetString("RomanticBetPlayer")); + if (BetTargetKnowRomantic.GetBool()) target.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Romantic), Translator.GetString("RomanticBetOnYou"))); if (RomanticGetsPartnerConvertedAddons.GetBool() && Partner.IsConverted()) Partner.GetCustomSubRoles().DoIf(x => x.IsConverted() && !RomanticPC.Is(x), x => RomanticPC.RpcSetCustomRole(x)); @@ -190,8 +188,8 @@ public class Romantic : RoleBase RomanticPC.SetKillCooldown(); RomanticPC.RPCPlayCustomSound("Shield"); - RomanticPC.Notify(GetString("RomanticProtectPartner")); - Partner.Notify(GetString("RomanticIsProtectingYou")); + RomanticPC.Notify(Translator.GetString("RomanticProtectPartner")); + Partner.Notify(Translator.GetString("RomanticIsProtectingYou")); LateTask.New(() => { @@ -201,8 +199,8 @@ public class Romantic : RoleBase if (!GameStates.IsInTask) return; - RomanticPC.Notify(GetString("ProtectingOver")); - Partner.Notify(GetString("ProtectingOver")); + RomanticPC.Notify(Translator.GetString("ProtectingOver")); + Partner.Notify(Translator.GetString("ProtectingOver")); RomanticPC.SetKillCooldown(); }, ProtectDuration.GetFloat(), "RomanticProtecting"); @@ -241,7 +239,7 @@ public class Romantic : RoleBase if (seer.PlayerId != RomanticId || !seer.Is(CustomRoles.Romantic)) return string.Empty; Color color = !HasPickedPartner ? Color.white : Utils.GetRoleColor(CustomRoles.Romantic); - string text = !HasPickedPartner ? GetString("Romantic.PickPartnerText") : "♥"; + string text = !HasPickedPartner ? Translator.GetString("Romantic.PickPartnerText") : "♥"; if (Arrows.GetBool()) text += TargetArrow.GetArrows(seer, PartnerId); return Utils.ColorString(color, text); @@ -264,7 +262,15 @@ public class Romantic : RoleBase private static void ChangeRole() { - if (Partner == null || RomanticPC == null || !RomanticPC.Is(CustomRoles.Romantic)) return; + if (RomanticPC == null || !RomanticPC.Is(CustomRoles.Romantic)) return; + + if (Partner == null) + { + Logger.Info("Romantic Partner is null => Changing to Ruthless Romantic", "Romantic"); + RomanticPC.RpcSetCustomRole(CustomRoles.RuthlessRomantic); + RomanticPC.SetKillCooldown(); + return; + } CustomRoles partnerRole = Partner.GetCustomRole(); PlayerControl killer = Partner.GetRealKiller(); @@ -326,7 +332,7 @@ public class Romantic : RoleBase public override void SetButtonTexts(HudManager hud, byte id) { - hud.KillButton?.OverrideText(!HasPickedPartner ? GetString("RomanticKillButtonText") : GetString("MedicalerButtonText")); + hud.KillButton?.OverrideText(!HasPickedPartner ? Translator.GetString("RomanticKillButtonText") : Translator.GetString("MedicalerButtonText")); } } @@ -406,7 +412,7 @@ public class VengefulRomantic : RoleBase public override void SetButtonTexts(HudManager hud, byte id) { - hud.KillButton?.OverrideText(GetString("VengefulRomanticKillButtonText")); + hud.KillButton?.OverrideText(Translator.GetString("VengefulRomanticKillButtonText")); } public override void ApplyGameOptions(IGameOptions opt, byte playerId)