using EHR.Modules; using EHR.Roles.AddOns.Common; using EHR.Roles.Crewmate; using EHR.Roles.Neutral; using HarmonyLib; using Hazel; using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using TMPro; using UnityEngine; using UnityEngine.Events; using static EHR.Translator; using Object = UnityEngine.Object; namespace EHR; public static class GuessManager { public static string GetFormatString() { string text = GetString("PlayerIdList"); foreach (PlayerControl pc in Main.AllAlivePlayerControls) { string id = pc.PlayerId.ToString(); string name = pc.GetRealName(); text += $"\n{id} → {name}"; } return text; } public static bool CheckCommand(ref string msg, string command, bool exact = true) { var comList = command.Split('|'); foreach (string str in comList) { if (exact) { if (msg == "/" + str) return true; } else { if (msg.StartsWith("/" + str)) { msg = msg.Replace("/" + str, string.Empty); return true; } } } return false; } public static byte GetColorFromMsg(string msg) { if (ConfirmIncludeMsg(msg, "红|紅|red")) return 0; if (ConfirmIncludeMsg(msg, "蓝|藍|深蓝|blue")) return 1; if (ConfirmIncludeMsg(msg, "绿|綠|深绿|green")) return 2; if (ConfirmIncludeMsg(msg, "粉红|粉紅|pink")) return 3; if (ConfirmIncludeMsg(msg, "橘|橘|orange")) return 4; if (ConfirmIncludeMsg(msg, "黄|黃|yellow")) return 5; if (ConfirmIncludeMsg(msg, "黑|黑|black")) return 6; if (ConfirmIncludeMsg(msg, "白|白|white")) return 7; if (ConfirmIncludeMsg(msg, "紫|紫|perple")) return 8; if (ConfirmIncludeMsg(msg, "棕|棕|brown")) return 9; if (ConfirmIncludeMsg(msg, "青|青|cyan")) return 10; if (ConfirmIncludeMsg(msg, "黄绿|黃綠|浅绿|lime")) return 11; if (ConfirmIncludeMsg(msg, "红褐|紅褐|深红|maroon")) return 12; if (ConfirmIncludeMsg(msg, "玫红|玫紅|浅粉|rose")) return 13; if (ConfirmIncludeMsg(msg, "焦黄|焦黃|淡黄|banana")) return 14; if (ConfirmIncludeMsg(msg, "灰|灰|gray")) return 15; if (ConfirmIncludeMsg(msg, "茶|茶|tan")) return 16; if (ConfirmIncludeMsg(msg, "珊瑚|珊瑚|coral")) return 17; return byte.MaxValue; } private static bool ConfirmIncludeMsg(string msg, string key) { var keys = key.Split('|'); return keys.Any(msg.Contains); } public static bool GuesserMsg(PlayerControl pc, string msg, bool isUI = false) { var originMsg = msg; if (!AmongUsClient.Instance.AmHost) return false; if (!GameStates.IsVoting || pc == null) return false; if (!pc.Is(CustomRoles.NiceGuesser) && !pc.Is(CustomRoles.EvilGuesser) && !pc.Is(CustomRoles.Doomsayer) && !pc.Is(CustomRoles.Judge) && !pc.Is(CustomRoles.NiceSwapper) && !pc.Is(CustomRoles.Councillor) && !pc.Is(CustomRoles.Guesser) && !Options.GuesserMode.GetBool()) return false; int operate; // 1: ID, 2: Guess msg = msg.ToLower().TrimStart().TrimEnd(); if (CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id")) operate = 1; else if (CheckCommand(ref msg, "shoot|guess|bet|st|gs|bt|猜|赌", false)) operate = 2; else return false; Logger.Msg(msg, "Msg Guesser"); Logger.Msg($"{operate}", "Operate"); if (!pc.IsAlive()) { if (!isUI) Utils.SendMessage(GetString("GuessDead"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDead")); return true; } if (!pc.Is(CustomRoles.NiceGuesser)) { if (pc.IsCrewmate() && !Options.CrewmatesCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Judge) && !pc.Is(CustomRoles.NiceSwapper)) { if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotAllowed")); return true; } } if (!pc.Is(CustomRoles.EvilGuesser)) { if (pc.GetCustomRole().IsImpostor() && !Options.ImpostorsCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Councillor)) { if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotAllowed")); return true; } } if (pc.IsNeutralKiller() && !Options.NeutralKillersCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser)) { if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotAllowed")); return true; } if (pc.GetCustomRole().IsNonNK() && !Options.PassiveNeutralsCanGuess.GetBool() && !pc.Is(CustomRoles.Guesser) && !pc.Is(CustomRoles.Doomsayer)) { if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotAllowed")); return true; } switch (operate) { case 1: Utils.SendMessage(GetFormatString(), pc.PlayerId); return true; case 2: { if ( (pc.Is(CustomRoles.NiceGuesser) && Options.GGTryHideMsg.GetBool()) || (pc.Is(CustomRoles.EvilGuesser) && Options.EGTryHideMsg.GetBool()) || (pc.Is(CustomRoles.Doomsayer) && Doomsayer.DoomsayerTryHideMsg.GetBool()) || (pc.Is(CustomRoles.Guesser) && Options.GTryHideMsg.GetBool()) || (Options.GuesserMode.GetBool() && Options.HideGuesserCommands.GetBool()) ) /*TryHideMsg();*/ ChatManager.SendPreviousMessagesToAll(); else if (pc.AmOwner && !isUI) Utils.SendMessage(originMsg, 255, pc.GetRealName()); if (!MsgToPlayerAndRole(msg, out byte targetId, out CustomRoles role, out string error)) { if (!isUI) Utils.SendMessage(error, pc.PlayerId); else pc.ShowPopUp(error); return true; } var target = Utils.GetPlayerById(targetId); if (target != null) { bool guesserSuicide = false; if (CopyCat.PlayerIdList.Contains(pc.PlayerId)) { if (!isUI) Utils.SendMessage(GetString("GuessDisabled"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDisabled")); return true; } Main.GuesserGuessed.TryAdd(pc.PlayerId, 0); switch (pc.GetCustomRole()) { case CustomRoles.NiceGuesser when Main.GuesserGuessed[pc.PlayerId] >= Options.GGCanGuessTime.GetInt(): if (!isUI) Utils.SendMessage(GetString("GGGuessMax"), pc.PlayerId); else pc.ShowPopUp(GetString("GGGuessMax")); return true; case CustomRoles.EvilGuesser when Main.GuesserGuessed[pc.PlayerId] >= Options.EGCanGuessTime.GetInt(): if (!isUI) Utils.SendMessage(GetString("EGGuessMax"), pc.PlayerId); else pc.ShowPopUp(GetString("EGGuessMax")); return true; case CustomRoles.Phantom when !Options.PhantomCanGuess.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessDisabled"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDisabled")); return true; case CustomRoles.Terrorist when !Options.TerroristCanGuess.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessDisabled"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDisabled")); return true; case CustomRoles.Workaholic when !Options.WorkaholicCanGuess.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessDisabled"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDisabled")); return true; case CustomRoles.God when !Options.GodCanGuess.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessDisabled"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDisabled")); return true; case CustomRoles.Monarch when role == CustomRoles.Knighted: if (!isUI) Utils.SendMessage(GetString("GuessKnighted"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessKnighted")); return true; case CustomRoles.Doomsayer: if (Doomsayer.CantGuess) { if (!isUI) Utils.SendMessage(GetString("DoomsayerCantGuess"), pc.PlayerId); else pc.ShowPopUp(GetString("DoomsayerCantGuess")); return true; } if (role.IsImpostor() && !Doomsayer.DCanGuessImpostors.GetBool()) { if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotAllowed")); return true; } if (target.IsCrewmate() && !Doomsayer.DCanGuessCrewmates.GetBool()) { if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotAllowed")); return true; } if (role.IsNeutral() && !Doomsayer.DCanGuessNeutrals.GetBool()) { if (!isUI) Utils.SendMessage(GetString("GuessNotAllowed"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotAllowed")); return true; } if (role.IsAdditionRole() && !Doomsayer.DCanGuessAdt.GetBool()) { if (!isUI) Utils.SendMessage(GetString("GuessAdtRole"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessAdtRole")); return true; } break; } if (Medic.ProtectList.Contains(target.PlayerId) && !Medic.GuesserIgnoreShield.GetBool()) { if (!isUI) Utils.SendMessage(GetString("GuessShielded"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessShielded")); return true; } switch (target.GetCustomRole()) { case CustomRoles.Workaholic when Options.WorkaholicVisibleToEveryone.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessWorkaholic"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessWorkaholic")); return true; case CustomRoles.Doctor when Options.DoctorVisibleToEveryone.GetBool() && !target.HasEvilAddon(): if (!isUI) Utils.SendMessage(GetString("GuessDoctor"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDoctor")); return true; case CustomRoles.Monarch when role == CustomRoles.Monarch && pc.Is(CustomRoles.Knighted): if (!isUI) Utils.SendMessage(GetString("GuessMonarch"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessMonarch")); return true; case CustomRoles.Mayor when Mayor.MayorRevealWhenDoneTasks.GetBool() && target.GetTaskState().IsTaskFinished: if (!isUI) Utils.SendMessage(GetString("GuessMayor"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessMayor")); return true; case CustomRoles.Bait when role == CustomRoles.Bait && Options.BaitNotification.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessNotifiedBait"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessNotifiedBait")); return true; case CustomRoles.Pestilence: if (!isUI) Utils.SendMessage(GetString("GuessPestilence"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessPestilence")); guesserSuicide = true; break; case CustomRoles.Phantom when role == CustomRoles.Phantom: if (!isUI) Utils.SendMessage(GetString("GuessPhantom"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessPhantom")); return true; case CustomRoles.Snitch when target.GetTaskState().RemainingTasksCount <= Snitch.RemainingTasksToBeFound: if (!isUI) Utils.SendMessage(GetString("EGGuessSnitchTaskDone"), pc.PlayerId); else pc.ShowPopUp(GetString("EGGuessSnitchTaskDone")); return true; case CustomRoles.Merchant when Merchant.IsBribedKiller(pc, target): if (!isUI) Utils.SendMessage(GetString("BribedByMerchant2"), pc.PlayerId); else pc.ShowPopUp(GetString("BribedByMerchant2")); return true; case CustomRoles.SuperStar: if (!isUI) Utils.SendMessage(GetString("GuessSuperStar"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessSuperStar")); return true; case CustomRoles.Disco: case CustomRoles.Glow: case CustomRoles.LastImpostor: if (!isUI) Utils.SendMessage(GetString("GuessObviousAddon"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessObviousAddon")); return true; case CustomRoles.GM: Utils.SendMessage(GetString("GuessGM"), pc.PlayerId); return true; default: switch (role) { case CustomRoles.SuperStar: if (!isUI) Utils.SendMessage(GetString("GuessSuperStar"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessSuperStar")); return true; case CustomRoles.GM: Utils.SendMessage(GetString("GuessGM"), pc.PlayerId); return true; } break; } if (target.Is(CustomRoles.Onbound)) { if (!isUI) Utils.SendMessage(GetString("GuessOnbound"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessOnbound")); return true; } if (Jailor.playerIdList.Any(x => Main.PlayerStates[x].Role is Jailor { IsEnable: true } jl && jl.JailorTarget == target.PlayerId)) { if (!isUI) Utils.SendMessage(GetString("CantGuessJailed"), pc.PlayerId, title: Utils.ColorString(Utils.GetRoleColor(CustomRoles.Jailor), GetString("JailorTitle"))); else pc.ShowPopUp(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Jailor), GetString("JailorTitle")) + "\n" + GetString("CantGuessJailed")); return true; } if (Jailor.playerIdList.Any(x => Main.PlayerStates[x].Role is Jailor { IsEnable: true } jl && jl.JailorTarget == pc.PlayerId && role != CustomRoles.Jailor)) { if (!isUI) Utils.SendMessage(GetString("JailedCanOnlyGuessJailor"), pc.PlayerId, title: Utils.ColorString(Utils.GetRoleColor(CustomRoles.Jailor), GetString("JailorTitle"))); else pc.ShowPopUp(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Jailor), GetString("JailorTitle")) + "\n" + GetString("JailedCanOnlyGuessJailor")); return true; } // Check whether add-on guessing is allowed switch (pc.GetCustomRole()) { // Assassin Cant Guess Addons case CustomRoles.EvilGuesser when role.IsAdditionRole() && !Options.EGCanGuessAdt.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessAdtRole"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessAdtRole")); return true; // Nice Guesser Cant Guess Addons case CustomRoles.NiceGuesser when role.IsAdditionRole() && !Options.GGCanGuessAdt.GetBool(): if (!isUI) Utils.SendMessage(GetString("GuessAdtRole"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessAdtRole")); return true; // Guesser (add-on) Cant Guess Addons default: if (role.IsAdditionRole() && pc.Is(CustomRoles.Guesser) && !Options.GCanGuessAdt.GetBool()) { if (!isUI) Utils.SendMessage(GetString("GuessAdtRole"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessAdtRole")); return true; } break; } // Guesser Mode Can/Cant Guess Addons if (Options.GuesserMode.GetBool()) { if (role.IsAdditionRole() && !Options.CanGuessAddons.GetBool()) { // Impostors Cant Guess Addons if (Options.ImpostorsCanGuess.GetBool() && pc.Is(CustomRoleTypes.Impostor) && !(pc.GetCustomRole() == CustomRoles.EvilGuesser || pc.Is(CustomRoles.Guesser))) { if (!isUI) Utils.SendMessage(GetString("GuessAdtRole"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessAdtRole")); return true; } // Crewmates Cant Guess Addons if (Options.CrewmatesCanGuess.GetBool() && pc.Is(CustomRoleTypes.Crewmate) && !(pc.GetCustomRole() == CustomRoles.NiceGuesser || pc.Is(CustomRoles.Guesser))) { if (!isUI) Utils.SendMessage(GetString("GuessAdtRole"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessAdtRole")); return true; } // Neutrals Cant Guess Addons if ((Options.NeutralKillersCanGuess.GetBool() || Options.PassiveNeutralsCanGuess.GetBool()) && pc.Is(CustomRoleTypes.Neutral) && !(pc.GetCustomRole() is CustomRoles.Ritualist or CustomRoles.Doomsayer || pc.Is(CustomRoles.Guesser))) { if (!isUI) Utils.SendMessage(GetString("GuessAdtRole"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessAdtRole")); return true; } } } if (pc.PlayerId == target.PlayerId) { if (pc.Is(CustomRoles.DoubleShot) && !DoubleShot.IsActive.Contains(pc.PlayerId)) { DoubleShot.IsActive.Add(pc.PlayerId); Logger.Msg($"{pc.PlayerId}", "GuesserDoubleShotIsActive-1"); if (!isUI) Utils.SendMessage(GetString("GuessDoubleShot"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDoubleShot")); return true; } if (pc.Is(CustomRoles.DoubleShot) && DoubleShot.IsActive.Contains(pc.PlayerId)) DoubleShot.IsActive.Remove(pc.PlayerId); if (!isUI) Utils.SendMessage(GetString("LaughToWhoGuessSelf"), pc.PlayerId, Utils.ColorString(Color.cyan, GetString("MessageFromKPD"))); else pc.ShowPopUp(Utils.ColorString(Color.cyan, GetString("MessageFromKPD")) + "\n" + GetString("LaughToWhoGuessSelf")); guesserSuicide = true; } else if (pc.Is(CustomRoles.NiceGuesser) && target.Is(CustomRoleTypes.Crewmate) && !Options.GGCanGuessCrew.GetBool() && !pc.Is(CustomRoles.Madmate)) { if (pc.Is(CustomRoles.DoubleShot) && !DoubleShot.IsActive.Contains(pc.PlayerId)) { DoubleShot.IsActive.Add(pc.PlayerId); Logger.Msg($"{pc.PlayerId}", "GuesserDoubleShotIsActive-2"); if (!isUI) Utils.SendMessage(GetString("GuessDoubleShot"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDoubleShot")); return true; } if (pc.Is(CustomRoles.DoubleShot) && DoubleShot.IsActive.Contains(pc.PlayerId)) DoubleShot.IsActive.Remove(pc.PlayerId); guesserSuicide = true; Logger.Msg($"{guesserSuicide}", "guesserSuicide1"); } else if (pc.Is(CustomRoles.EvilGuesser) && target.Is(CustomRoleTypes.Impostor) && !Options.EGCanGuessImp.GetBool()) { if (pc.Is(CustomRoles.DoubleShot) && !DoubleShot.IsActive.Contains(pc.PlayerId)) { DoubleShot.IsActive.Add(pc.PlayerId); Logger.Msg($"{pc.PlayerId}", "GuesserDoubleShotIsActive-3"); if (!isUI) Utils.SendMessage(GetString("GuessDoubleShot"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDoubleShot")); return true; } if (pc.Is(CustomRoles.DoubleShot) && DoubleShot.IsActive.Contains(pc.PlayerId)) DoubleShot.IsActive.Remove(pc.PlayerId); guesserSuicide = true; Logger.Msg($"{guesserSuicide}", "guesserSuicide2"); } // else if (pc.Is(CustomRoles.Guesser)/* && role.IsImpostor() && !Options.GCanGuessImp.GetBool()*/) guesserSuicide = true; // else if (pc.Is(CustomRoles.Guesser)/* && role.IsCrewmate() && !pc.Is(CustomRoles.Madmate) && !Options.GCanGuessCrew.GetBool() */) guesserSuicide = true; else if (!target.Is(role)) { if (pc.Is(CustomRoles.DoubleShot) && !DoubleShot.IsActive.Contains(pc.PlayerId)) { DoubleShot.IsActive.Add(pc.PlayerId); Logger.Msg($"{pc.PlayerId}", "GuesserDoubleShotIsActive-4"); if (!isUI) Utils.SendMessage(GetString("GuessDoubleShot"), pc.PlayerId); else pc.ShowPopUp(GetString("GuessDoubleShot")); return true; } if (pc.Is(CustomRoles.DoubleShot) && DoubleShot.IsActive.Contains(pc.PlayerId)) DoubleShot.IsActive.Remove(pc.PlayerId); guesserSuicide = true; Logger.Msg($"{guesserSuicide}", "guesserSuicide3"); } // ----------------------------------------------------------------------------------------------------------------------------------- Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} guessed {target.GetNameWithRole().RemoveHtmlTags()}", "Guesser"); var dp = guesserSuicide ? pc : target; target = dp; Logger.Info($"Player:{target.GetRealName().RemoveHtmlTags()} was guessed by {pc.GetRealName().RemoveHtmlTags()}", "Guesser"); Main.GuesserGuessed[pc.PlayerId]++; if (pc.Is(CustomRoles.Doomsayer) && Doomsayer.AdvancedSettings.GetBool()) { if (Doomsayer.GuessesCountPerMeeting >= Doomsayer.MaxNumberOfGuessesPerMeeting.GetInt() && pc.PlayerId != dp.PlayerId) { if (!isUI) Utils.SendMessage(GetString("DoomsayerCantGuess"), pc.PlayerId); else pc.ShowPopUp(GetString("DoomsayerCantGuess")); return true; } Doomsayer.GuessesCountPerMeeting++; if (Doomsayer.GuessesCountPerMeeting >= Doomsayer.MaxNumberOfGuessesPerMeeting.GetInt()) Doomsayer.CantGuess = true; if (!Doomsayer.KillCorrectlyGuessedPlayers.GetBool() && pc.PlayerId != dp.PlayerId) { if (!isUI) Utils.SendMessage(GetString("DoomsayerCorrectlyGuessRole"), pc.PlayerId); else pc.ShowPopUp(GetString("DoomsayerCorrectlyGuessRole")); if (Doomsayer.GuessedRoles.Contains(role)) { _ = new LateTask(() => { Utils.SendMessage(GetString("DoomsayerGuessSameRoleAgainMsg"), pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Doomsayer), GetString("DoomsayerGuessCountTitle"))); }, 0.7f, "Doomsayer Guess Same Role Again Msg"); } else { Doomsayer.GuessingToWin[pc.PlayerId]++; Doomsayer.SendRPC(pc); Doomsayer.GuessedRoles.Add(role); _ = new LateTask(() => { Utils.SendMessage(string.Format(GetString("DoomsayerGuessCountMsg"), Doomsayer.GuessingToWin[pc.PlayerId]), pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Doomsayer), GetString("DoomsayerGuessCountTitle"))); }, 0.7f, "Doomsayer Guess Msg 1"); } Doomsayer.CheckCountGuess(pc); return true; } if (Doomsayer.DoesNotSuicideWhenMisguessing.GetBool() && pc.PlayerId == dp.PlayerId) { if (!isUI) Utils.SendMessage(GetString("DoomsayerNotCorrectlyGuessRole"), pc.PlayerId); else pc.ShowPopUp(GetString("DoomsayerNotCorrectlyGuessRole")); if (Doomsayer.MisguessRolePrevGuessRoleUntilNextMeeting.GetBool()) { Doomsayer.CantGuess = true; } return true; } } string Name = dp.GetRealName(); if (!Options.DisableKillAnimationOnGuess.GetBool()) CustomSoundsManager.RPCPlayCustomSoundAll("Gunfire"); _ = new LateTask(() => { Main.PlayerStates[dp.PlayerId].deathReason = PlayerState.DeathReason.Gambled; dp.SetRealKiller(pc); dp.RpcGuesserMurderPlayer(); if (dp.Is(CustomRoles.Medic)) Medic.IsDead(dp); if (pc.Is(CustomRoles.Doomsayer) && pc.PlayerId != dp.PlayerId) { Doomsayer.GuessingToWin[pc.PlayerId]++; Doomsayer.SendRPC(pc); if (!Doomsayer.GuessedRoles.Contains(role)) Doomsayer.GuessedRoles.Add(role); Doomsayer.CheckCountGuess(pc); } GuessManagerRole.OnGuess(dp, pc); Utils.AfterPlayerDeathTasks(dp, true); Utils.NotifyRoles(isForMeeting: GameStates.IsMeeting, NoCache: true); _ = new LateTask(() => { Utils.SendMessage(string.Format(GetString("GuessKill"), Name), 255, Utils.ColorString(Utils.GetRoleColor(CustomRoles.NiceGuesser), GetString("GuessKillTitle"))); }, 0.6f, "Guess Msg"); if (pc.Is(CustomRoles.Doomsayer) && pc.PlayerId != dp.PlayerId) { _ = new LateTask(() => { Utils.SendMessage(string.Format(GetString("DoomsayerGuessCountMsg"), Doomsayer.GuessingToWin[pc.PlayerId]), pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Doomsayer), GetString("DoomsayerGuessCountTitle"))); }, 0.7f, "Doomsayer Guess Msg 2"); } }, 0.2f, "Guesser Kill"); } break; } } return true; } public static TextMeshPro NameText(this PlayerControl p) => p.cosmetics.nameText; public static TextMeshPro NameText(this PoolablePlayer p) => p.cosmetics.nameText; public static void RpcGuesserMurderPlayer(this PlayerControl pc /*, float delay = 0f*/) { // DEATH STUFF // var amOwner = pc.AmOwner; pc.Data.IsDead = true; pc.RpcExileV2(); Main.PlayerStates[pc.PlayerId].SetDead(); var meetingHud = MeetingHud.Instance; var hudManager = DestroyableSingleton.Instance; SoundManager.Instance.PlaySound(pc.KillSfx, false, 0.8f); if (!Options.DisableKillAnimationOnGuess.GetBool()) hudManager.KillOverlay.ShowKillAnimation(pc.Data, pc.Data); if (amOwner) { hudManager.ShadowQuad.gameObject.SetActive(false); pc.NameText().GetComponent().material.SetInt("_Mask", 0); pc.RpcSetScanner(false); ImportantTextTask importantTextTask = new GameObject("_Player").AddComponent(); importantTextTask.transform.SetParent(AmongUsClient.Instance.transform, false); meetingHud.SetForegroundForDead(); } PlayerVoteArea voteArea = MeetingHud.Instance.playerStates.First( x => x.TargetPlayerId == pc.PlayerId ); if (voteArea.DidVote) voteArea.UnsetVote(); voteArea.AmDead = true; voteArea.Overlay.gameObject.SetActive(true); voteArea.Overlay.color = Color.white; voteArea.XMark.gameObject.SetActive(true); voteArea.XMark.transform.localScale = Vector3.one; foreach (var playerVoteArea in meetingHud.playerStates) { if (playerVoteArea.VotedFor != pc.PlayerId) continue; playerVoteArea.UnsetVote(); var voteAreaPlayer = Utils.GetPlayerById(playerVoteArea.TargetPlayerId); if (!voteAreaPlayer.AmOwner) continue; meetingHud.ClearVote(); } MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.GuessKill, SendOption.Reliable); writer.Write(pc.PlayerId); AmongUsClient.Instance.FinishRpcImmediately(writer); } public static void RpcClientGuess(PlayerControl pc) { var amOwner = pc.AmOwner; var meetingHud = MeetingHud.Instance; var hudManager = DestroyableSingleton.Instance; SoundManager.Instance.PlaySound(pc.KillSfx, false, 0.8f); if (!Options.DisableKillAnimationOnGuess.GetBool()) hudManager.KillOverlay.ShowKillAnimation(pc.Data, pc.Data); if (amOwner) { hudManager.ShadowQuad.gameObject.SetActive(false); pc.NameText().GetComponent().material.SetInt("_Mask", 0); pc.RpcSetScanner(false); ImportantTextTask importantTextTask = new GameObject("_Player").AddComponent(); importantTextTask.transform.SetParent(AmongUsClient.Instance.transform, false); meetingHud.SetForegroundForDead(); } PlayerVoteArea voteArea = MeetingHud.Instance.playerStates.First( x => x.TargetPlayerId == pc.PlayerId ); if (voteArea.DidVote) voteArea.UnsetVote(); voteArea.AmDead = true; voteArea.Overlay.gameObject.SetActive(true); voteArea.Overlay.color = Color.white; voteArea.XMark.gameObject.SetActive(true); voteArea.XMark.transform.localScale = Vector3.one; foreach (var playerVoteArea in meetingHud.playerStates) { if (playerVoteArea.VotedFor != pc.PlayerId) continue; playerVoteArea.UnsetVote(); var voteAreaPlayer = Utils.GetPlayerById(playerVoteArea.TargetPlayerId); if (!voteAreaPlayer.AmOwner) continue; meetingHud.ClearVote(); } } public static bool MsgToPlayerAndRole(string msg, out byte id, out CustomRoles role, out string error) { if (msg.StartsWith("/")) msg = msg.Replace("/", string.Empty); Regex r = new("\\d+"); MatchCollection mc = r.Matches(msg); string result = string.Empty; for (int i = 0; i < mc.Count; i++) { result += mc[i]; // The matching result is a complete number, and no splicing is required here. } if (byte.TryParse(result, out byte num)) { id = num; } else { // It is not the player number, it determines whether it is the color or not. //byte color = GetColorFromMsg(msg); // Okay, I don’t know how to get the color of a certain player. I’ll fill it in later. id = byte.MaxValue; error = GetString("GuessHelp"); role = new(); return false; } // Determine whether the selected player is reasonable PlayerControl target = Utils.GetPlayerById(id); if (target == null || target.Data.IsDead) { error = GetString("GuessNull"); role = new(); return false; } if (!ChatCommands.GetRoleByName(msg, out role)) { error = GetString("GuessHelp"); return false; } error = string.Empty; return true; } /* public static void TryHideMsg() { ChatUpdatePatch.DoBlockChat = true; List roles = Enum.GetValues(typeof(CustomRoles)).Cast().Where(x => x is not CustomRoles.NotAssigned and not CustomRoles.KB_Normal).ToList(); var rd = IRandom.Instance; string msg = Utils.EmptyMessage(); string[] command = ["bet", "bt", "guess", "gs", "shoot", "st", "赌", "猜", "审判", "tl", "判", "审"]; var x = Main.AllAlivePlayerControls; var totalAlive = Main.AllAlivePlayerControls.Length; for (int i = 0; i < 20; i++) { //msg = "/"; //if (rd.Next(1, 100) < 20) //{ // msg += "id"; //} //else //{ // msg += command[rd.Next(0, command.Length - 1)]; // msg += rd.Next(1, 100) < 50 ? string.Empty : " "; // msg += rd.Next(0, 15).ToString(); // msg += rd.Next(1, 100) < 50 ? string.Empty : " "; // CustomRoles role = roles[rd.Next(0, roles.Count)]; // msg += rd.Next(1, 100) < 50 ? string.Empty : " "; // msg += Utils.GetRoleName(role); //} var player = x[rd.Next(0, totalAlive)]; DestroyableSingleton.Instance.Chat.AddChat(player, msg); var writer = CustomRpcSender.Create("MessagesToSend"); writer.StartMessage(); writer.StartRpc(player.NetId, (byte)RpcCalls.SendChat) .Write(msg) .EndRpc(); writer.EndMessage(); writer.SendMessage(); } ChatUpdatePatch.DoBlockChat = false; } */ [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] class StartMeetingPatch { public static void Postfix(MeetingHud __instance) { var lp = PlayerControl.LocalPlayer; bool alive = lp.IsAlive(); if (Options.GuesserMode.GetBool()) { CustomRoles role = lp.GetCustomRole(); if (alive && role.IsImpostor() && Options.ImpostorsCanGuess.GetBool()) CreateGuesserButton(__instance); else if (role is CustomRoles.EvilGuesser && !Options.ImpostorsCanGuess.GetBool()) CreateGuesserButton(__instance); if (alive && lp.IsCrewmate() && Options.CrewmatesCanGuess.GetBool()) CreateGuesserButton(__instance); else if (role is CustomRoles.NiceGuesser && !Options.CrewmatesCanGuess.GetBool()) CreateGuesserButton(__instance); if (alive && lp.IsNeutralKiller() && Options.NeutralKillersCanGuess.GetBool()) CreateGuesserButton(__instance); if (alive && role.IsNonNK() && Options.PassiveNeutralsCanGuess.GetBool()) CreateGuesserButton(__instance); else if (role is CustomRoles.Doomsayer && !Options.PassiveNeutralsCanGuess.GetBool() && !Doomsayer.CantGuess) CreateGuesserButton(__instance); } else { if (alive && lp.Is(CustomRoles.EvilGuesser)) CreateGuesserButton(__instance); if (alive && lp.Is(CustomRoles.NiceGuesser)) CreateGuesserButton(__instance); if (alive && lp.Is(CustomRoles.Doomsayer) && !Doomsayer.CantGuess) CreateGuesserButton(__instance); if (alive && lp.Is(CustomRoles.Guesser)) CreateGuesserButton(__instance); } } } public static void CreateGuesserButton(MeetingHud __instance) { foreach (var pva in __instance.playerStates) { var pc = Utils.GetPlayerById(pva.TargetPlayerId); if (pc == null || !pc.IsAlive()) continue; GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; GameObject targetBox = Object.Instantiate(template, pva.transform); targetBox.name = "ShootButton"; targetBox.transform.localPosition = new(-0.95f, 0.03f, -1.31f); SpriteRenderer renderer = targetBox.GetComponent(); renderer.sprite = CustomButton.Get("TargetIcon"); PassiveButton button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); var pva1 = pva; button.OnClick.AddListener((Action)(() => GuesserOnClick(pva1.TargetPlayerId, __instance))); } } public const int MaxOneScreenRole = 40; public static int Page; public static PassiveButton ExitButton; public static GameObject guesserUI; private static Dictionary> RoleButtons; private static Dictionary RoleSelectButtons; private static List PageButtons; public static CustomRoleTypes currentTeamType; static void GuesserSelectRole(CustomRoleTypes Role, bool SetPage = true) { currentTeamType = Role; if (SetPage) Page = 1; foreach (var RoleButton in RoleButtons) { int index = 0; foreach (var RoleBtn in RoleButton.Value) { if (RoleBtn == null) continue; index++; if (index <= (Page - 1) * 40) { RoleBtn.gameObject.SetActive(false); continue; } if ((Page * 40) < index) { RoleBtn.gameObject.SetActive(false); continue; } RoleBtn.gameObject.SetActive(RoleButton.Key == Role); } } foreach (var RoleButton in RoleSelectButtons) { if (RoleButton.Value == null) continue; RoleButton.Value.color = new(0, 0, 0, RoleButton.Key == Role ? 1 : 0.25f); } } public static TextMeshPro textTemplate; static void GuesserOnClick(byte playerId, MeetingHud __instance) { var pc = Utils.GetPlayerById(playerId); if (pc == null || !pc.IsAlive() || guesserUI != null || !GameStates.IsVoting) return; try { Page = 1; RoleButtons = []; RoleSelectButtons = []; PageButtons = []; __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(false)); Transform container = Object.Instantiate(GameObject.Find("PhoneUI").transform, __instance.transform); container.transform.localPosition = new(0, 0, -200f); guesserUI = container.gameObject; List i = [0, 0, 0, 0]; var buttonTemplate = __instance.playerStates[0].transform.FindChild("votePlayerBase"); var maskTemplate = __instance.playerStates[0].transform.FindChild("MaskArea"); var smallButtonTemplate = __instance.playerStates[0].Buttons.transform.Find("CancelButton"); textTemplate.enabled = true; if (textTemplate.transform.FindChild("RoleTextMeeting") != null) Object.Destroy(textTemplate.transform.FindChild("RoleTextMeeting").gameObject); Transform exitButtonParent = new GameObject().transform; exitButtonParent.SetParent(container); Transform exitButton = Object.Instantiate(buttonTemplate, exitButtonParent); exitButton.FindChild("ControllerHighlight").gameObject.SetActive(false); Transform exitButtonMask = Object.Instantiate(maskTemplate, exitButtonParent); exitButtonMask.transform.localScale = new(2.88f, 0.8f, 1f); exitButtonMask.transform.localPosition = new(0f, 0f, 1f); exitButton.gameObject.GetComponent().sprite = smallButtonTemplate.GetComponent().sprite; exitButtonParent.transform.localPosition = new(3.88f, 2.12f, -200f); exitButtonParent.transform.localScale = new(0.22f, 0.9f, 1f); exitButtonParent.transform.SetAsFirstSibling(); exitButton.GetComponent().OnClick.RemoveAllListeners(); exitButton.GetComponent().OnClick.AddListener((Action)(() => { __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(true)); Object.Destroy(container.gameObject); })); ExitButton = exitButton.GetComponent(); List buttons = []; Transform selectedButton = null; int tabCount = 0; for (int index = 0; index < 4; index++) { if (PlayerControl.LocalPlayer.Is(CustomRoles.EvilGuesser)) { if (!Options.EGCanGuessImp.GetBool() && index == 1) continue; if (!Options.EGCanGuessAdt.GetBool() && index == 3) continue; } else if (PlayerControl.LocalPlayer.Is(CustomRoles.NiceGuesser)) { if (!Options.GGCanGuessCrew.GetBool() && index == 0) continue; if (!Options.GGCanGuessAdt.GetBool() && index == 3) continue; } else if (PlayerControl.LocalPlayer.Is(CustomRoles.Doomsayer)) { if (!Doomsayer.DCanGuessCrewmates.GetBool() && index == 0) continue; if (!Doomsayer.DCanGuessImpostors.GetBool() && index == 1) continue; if (!Doomsayer.DCanGuessNeutrals.GetBool() && index == 2) continue; if (!Doomsayer.DCanGuessAdt.GetBool() && index == 3) continue; } else if (PlayerControl.LocalPlayer.Is(CustomRoles.Guesser)) { if (!Options.GCanGuessCrew.GetBool() && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Crewmate) && index == 0) continue; if (!Options.GCanGuessImp.GetBool() && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Impostor) && index == 1) continue; if (!Options.GCanGuessAdt.GetBool() && index == 3) continue; } else if (Options.GuesserMode.GetBool()) { if (!Options.CrewCanGuessCrew.GetBool() && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Crewmate) && index == 0) continue; if (!Options.ImpCanGuessImp.GetBool() && PlayerControl.LocalPlayer.Is(CustomRoleTypes.Impostor) && index == 1) continue; // if (index == 2) continue; if (!Options.CanGuessAddons.GetBool() && index == 3) continue; } Transform TeambuttonParent = new GameObject().transform; TeambuttonParent.SetParent(container); Transform Teambutton = Object.Instantiate(buttonTemplate, TeambuttonParent); Teambutton.FindChild("ControllerHighlight").gameObject.SetActive(false); Transform TeambuttonMask = Object.Instantiate(maskTemplate, TeambuttonParent); TextMeshPro Teamlabel = Object.Instantiate(textTemplate, Teambutton); Teambutton.GetComponent().sprite = CustomButton.Get("GuessPlateWithKPD"); RoleSelectButtons.Add((CustomRoleTypes)index, Teambutton.GetComponent()); TeambuttonParent.localPosition = new(-2.75f + (tabCount++ * 1.73f), 2.225f, -200); TeambuttonParent.localScale = new(0.53f, 0.53f, 1f); Teamlabel.color = (CustomRoleTypes)index switch { CustomRoleTypes.Crewmate => new(140, 255, 255, byte.MaxValue), CustomRoleTypes.Impostor => new(255, 25, 25, byte.MaxValue), CustomRoleTypes.Neutral => new(255, 171, 27, byte.MaxValue), CustomRoleTypes.Addon => new Color32(255, 154, 206, byte.MaxValue), _ => throw new NotImplementedException(), }; Logger.Info(Teamlabel.color.ToString(), ((CustomRoleTypes)index).ToString()); Teamlabel.text = GetString("Type" + ((CustomRoleTypes)index)); Teamlabel.alignment = TextAlignmentOptions.Center; Teamlabel.transform.localPosition = new(0, 0, Teamlabel.transform.localPosition.z); Teamlabel.transform.localScale *= 1.6f; Teamlabel.autoSizeTextContainer = true; if (PlayerControl.LocalPlayer.IsAlive()) CreateTeamButton(Teambutton, (CustomRoleTypes)index); continue; static void CreateTeamButton(Component Teambutton, CustomRoleTypes type) { Teambutton.GetComponent().OnClick.AddListener((UnityAction)(() => { GuesserSelectRole(type); ReloadPage(); })); } } static void ReloadPage() { PageButtons[0].color = new(1, 1, 1, 1f); PageButtons[1].color = new(1, 1, 1, 1f); if ((RoleButtons[currentTeamType].Count / MaxOneScreenRole + (RoleButtons[currentTeamType].Count % MaxOneScreenRole != 0 ? 1 : 0)) < Page) { Page -= 1; PageButtons[1].color = new(1, 1, 1, 0.1f); } else if ((RoleButtons[currentTeamType].Count / MaxOneScreenRole + (RoleButtons[currentTeamType].Count % MaxOneScreenRole != 0 ? 1 : 0)) < Page + 1) { PageButtons[1].color = new(1, 1, 1, 0.1f); } if (Page <= 1) { Page = 1; PageButtons[0].color = new(1, 1, 1, 0.1f); } GuesserSelectRole(currentTeamType, false); } static void CreatePage(bool IsNext, MeetingHud __instance, Transform container) { var buttonTemplate = __instance.playerStates[0].transform.FindChild("votePlayerBase"); var maskTemplate = __instance.playerStates[0].transform.FindChild("MaskArea"); var smallButtonTemplate = __instance.playerStates[0].Buttons.transform.Find("CancelButton"); Transform PagebuttonParent = new GameObject().transform; PagebuttonParent.SetParent(container); Transform Pagebutton = Object.Instantiate(buttonTemplate, PagebuttonParent); Pagebutton.FindChild("ControllerHighlight").gameObject.SetActive(false); Transform PagebuttonMask = Object.Instantiate(maskTemplate, PagebuttonParent); TextMeshPro Pagelabel = Object.Instantiate(textTemplate, Pagebutton); Pagebutton.GetComponent().sprite = CustomButton.Get("GuessPlateWithKPD"); PagebuttonParent.localPosition = IsNext ? new(3.535f, -2.2f, -200) : new(-3.475f, -2.2f, -200); PagebuttonParent.localScale = new(0.55f, 0.55f, 1f); Pagelabel.color = Color.white; Pagelabel.text = GetString(IsNext ? "NextPage" : "PreviousPage"); Pagelabel.alignment = TextAlignmentOptions.Center; Pagelabel.transform.localPosition = new(0, 0, Pagelabel.transform.localPosition.z); Pagelabel.transform.localScale *= 1.6f; Pagelabel.autoSizeTextContainer = true; if (!IsNext && Page <= 1) Pagebutton.GetComponent().color = new(1, 1, 1, 0.1f); Pagebutton.GetComponent().OnClick.AddListener((Action)(() => ClickEvent())); PageButtons.Add(Pagebutton.GetComponent()); return; void ClickEvent() { if (IsNext) Page += 1; else Page -= 1; if (Page < 1) Page = 1; ReloadPage(); } } if (PlayerControl.LocalPlayer.IsAlive()) { CreatePage(false, __instance, container); CreatePage(true, __instance, container); } var sortedRoles = EnumHelper.GetAllValues().OrderBy(x => GetString($"{x}")).ToArray(); foreach (var role in sortedRoles) { if (role is CustomRoles.GM or CustomRoles.SpeedBooster or CustomRoles.Engineer or CustomRoles.Crewmate or CustomRoles.Oblivious or CustomRoles.Rogue or CustomRoles.Scientist or CustomRoles.Impostor or CustomRoles.Shapeshifter or CustomRoles.Flashman or CustomRoles.Disco or CustomRoles.Giant or CustomRoles.NotAssigned or CustomRoles.KB_Normal or CustomRoles.Paranoia or CustomRoles.SuperStar or CustomRoles.Konan or CustomRoles.Oblivious or CustomRoles.GuardianAngelEHR ) continue; if (!role.IsEnable() && !role.RoleExist(countDead: true) && !role.IsConverted()) continue; CreateRole(role); } void CreateRole(CustomRoles role) { if (40 <= i[(int)role.GetCustomRoleTypes()]) i[(int)role.GetCustomRoleTypes()] = 0; Transform buttonParent = new GameObject().transform; buttonParent.SetParent(container); Transform button = Object.Instantiate(buttonTemplate, buttonParent); button.FindChild("ControllerHighlight").gameObject.SetActive(false); Transform buttonMask = Object.Instantiate(maskTemplate, buttonParent); TextMeshPro label = Object.Instantiate(textTemplate, button); button.GetComponent().sprite = CustomButton.Get("GuessPlate"); if (!RoleButtons.ContainsKey(role.GetCustomRoleTypes())) { RoleButtons.Add(role.GetCustomRoleTypes(), []); } RoleButtons[role.GetCustomRoleTypes()].Add(button); buttons.Add(button); int row = i[(int)role.GetCustomRoleTypes()] / 5; int col = i[(int)role.GetCustomRoleTypes()] % 5; buttonParent.localPosition = new(-3.47f + 1.75f * col, 1.5f - 0.45f * row, -200f); buttonParent.localScale = new(0.55f, 0.55f, 1f); label.text = GetString(role.ToString()); label.color = Utils.GetRoleColor(role); label.alignment = TextAlignmentOptions.Center; label.transform.localPosition = new(0, 0, label.transform.localPosition.z); label.transform.localScale *= 1.6f; label.autoSizeTextContainer = true; _ = i[(int)role.GetCustomRoleTypes()]; button.GetComponent().OnClick.RemoveAllListeners(); if (PlayerControl.LocalPlayer.IsAlive()) button.GetComponent().OnClick.AddListener((Action)(() => { if (selectedButton != button) { selectedButton = button; buttons.ForEach(x => x.GetComponent().color = x == selectedButton ? Utils.GetRoleColor(PlayerControl.LocalPlayer.GetCustomRole()) : Color.white); } else { if (!(__instance.state == MeetingHud.VoteStates.Voted || __instance.state == MeetingHud.VoteStates.NotVoted) || !PlayerControl.LocalPlayer.IsAlive()) return; Logger.Msg($"Click: {pc.GetNameWithRole().RemoveHtmlTags()} => {role}", "Guesser UI"); if (AmongUsClient.Instance.AmHost) GuesserMsg(PlayerControl.LocalPlayer, $"/bt {playerId} {GetString(role.ToString())}", true); else SendRPC(playerId, role); // Reset the GUI __instance.playerStates.ToList().ForEach(x => x.gameObject.SetActive(true)); Object.Destroy(container.gameObject); textTemplate.enabled = false; } })); i[(int)role.GetCustomRoleTypes()]++; } container.transform.localScale *= 0.75f; GuesserSelectRole(CustomRoleTypes.Crewmate); ReloadPage(); } catch (Exception ex) { Logger.Exception(ex, "Guesser UI"); return; } PlayerControl.LocalPlayer.RPCPlayCustomSound("Gunload"); } [HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.OnDestroy))] class MeetingHudOnDestroyGuesserUIClose { public static void Postfix() { Object.Destroy(textTemplate.gameObject); } } // Modded non-host client guess role/add-on private static void SendRPC(int playerId, CustomRoles role) { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (int)CustomRPC.Guess, SendOption.Reliable); writer.Write(playerId); writer.Write((int)role); AmongUsClient.Instance.FinishRpcImmediately(writer); } public static void ReceiveRPC(MessageReader reader, PlayerControl pc) { Logger.Msg($"{reader}", "MessageReader reader"); Logger.Msg($"{pc}", "PlayerControl pc"); int PlayerId = reader.ReadInt32(); Logger.Msg($"{PlayerId}", "Player Id"); CustomRoles role = (CustomRoles)reader.ReadInt32(); Logger.Msg($"{role}", "Role Int32"); Logger.Msg($"{GetString(role.ToString())}", "Role String"); GuesserMsg(pc, $"/bt {PlayerId} {GetString(role.ToString())}", true); } }