diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index a4ae2b271..cb38ba558 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -56,7 +56,7 @@ internal static class ExtendedPlayerControl public bool UsesMeetingShapeshift() { CustomRoles role = player.GetCustomRole(); - if (player.IsModdedClient() && role is CustomRoles.Councillor or CustomRoles.Inspector or CustomRoles.Judge or CustomRoles.Retributionist or CustomRoles.Starspawn or CustomRoles.Swapper or CustomRoles.Ventriloquist) return false; + // if (player.IsModdedClient() && role is CustomRoles.Councillor or CustomRoles.Inspector or CustomRoles.Judge or CustomRoles.Retributionist or CustomRoles.Starspawn or CustomRoles.Swapper or CustomRoles.Ventriloquist) return false; return role.UsesMeetingShapeshift(); } diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index 550193d5d..9b051b077 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -795,7 +795,7 @@ public static class GuessManager } } - private static void GuesserOnClick(byte playerId, MeetingHud __instance) + public static void GuesserOnClick(byte playerId, MeetingHud __instance, bool specificRoleChoosing = false) { PlayerControl pc = Utils.GetPlayerById(playerId); if (!pc || !pc.IsAlive() || GuesserUI || MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding || Starspawn.IsDayBreak) return; @@ -855,6 +855,13 @@ public static class GuessManager case (CustomRoles.EvilGuesser, 4) when !Options.EGCanGuessAdt.GetBool(): case (CustomRoles.NiceGuesser, 0) when !Options.GGCanGuessCrew.GetBool() && !PlayerControl.LocalPlayer.IsMadmate(): case (CustomRoles.NiceGuesser, 4) when !Options.GGCanGuessAdt.GetBool(): + case (CustomRoles.Loner, 0) when specificRoleChoosing: + case (CustomRoles.Loner, 2) when specificRoleChoosing: + case (CustomRoles.Loner, 3) when specificRoleChoosing: + case (CustomRoles.Loner, 4) when specificRoleChoosing: + case (CustomRoles.Inquirer, 4) when specificRoleChoosing: + case (CustomRoles.Forger, 4) when specificRoleChoosing: + case (CustomRoles.Pawn, 4) when specificRoleChoosing: continue; } @@ -971,7 +978,7 @@ public static class GuessManager foreach (CustomRoles role in Main.CustomRoleValues) { - if (!ShowRoleOnUI(role)) continue; + if (!ShowRoleOnUI(role, specificRoleChoosing)) continue; CreateRole(role); } @@ -1024,8 +1031,35 @@ public static class GuessManager Logger.Msg($"Click: {pc.GetNameWithRole()} => {role}", "Guesser UI"); - if (AmongUsClient.Instance.AmHost) GuesserMsg(PlayerControl.LocalPlayer, $"/bt {playerId} {GetString(role.ToString())}", true); - else SendRPC(playerId, role); + if (specificRoleChoosing) + switch(PlayerControl.LocalPlayer.GetCustomRole()) + { + case CustomRoles.Loner: + { + Loner.ProcessGuesserUI(playerId, role); + break; + } + case CustomRoles.Inquirer: + { + Inquirer.ProcessGuesserUI(playerId, role); + break; + } + case CustomRoles.Forger: + { + Forger.ProcessGuesserUI(playerId, role); + break; + } + case CustomRoles.Pawn: + { + Pawn.ProcessGuesserUI(role); + break; + } + } + else + { + 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)); @@ -1039,7 +1073,7 @@ public static class GuessManager } container.transform.localScale *= 0.75f; - GuesserSelectRole(CustomRoleTypes.Neutral); + GuesserSelectRole(specificRoleChoosing ? CustomRoleTypes.Impostor : CustomRoleTypes.Neutral); ReloadPage(); } catch (Exception ex) @@ -1051,10 +1085,12 @@ public static class GuessManager CustomSoundsManager.Play("Gunload"); } - private static bool ShowRoleOnUI(CustomRoles role) + private static bool ShowRoleOnUI(CustomRoles role, bool specificRoleChoosing = false) { + if (role is CustomRoles.GM or CustomRoles.NotAssigned ) + return false; + if (role is - CustomRoles.GM or CustomRoles.Ankylosaurus or CustomRoles.BananaMan or CustomRoles.Car or @@ -1062,12 +1098,11 @@ public static class GuessManager CustomRoles.Flash or CustomRoles.Giant or CustomRoles.LastImpostor or - CustomRoles.NotAssigned or CustomRoles.Shifter or CustomRoles.Specter or CustomRoles.SuperStar ) - return false; + return specificRoleChoosing; if (role.IsForOtherGameMode()) return false; if (!role.IsEnable() && !role.RoleExist(true) && !CanMakeRoleSpawn(role)) return false; diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 8d85149a3..d69675e1f 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -724,7 +724,6 @@ public static class Options public static OptionItem AnagramLanguage; public static OptionItem AnagramWordLength; public static OptionItem AnagramDifficulty; - public static OptionItem EightballCommandIndexes; public static OptionItem LadderDeath; public static OptionItem LadderDeathChance; @@ -3039,9 +3038,6 @@ public static class Options ], 0, TabGroup.GameSettings) .SetColor(new Color32(100, 220, 255, byte.MaxValue)); - EightballCommandIndexes = new IntegerOptionItem(23820, "EightballCommandIndexes", new(1, 100, 1), 20, TabGroup.GameSettings) - .SetColor(new Color32(100, 220, 255, byte.MaxValue)); - new TextOptionItem(100028, "MenuTitle.Other", TabGroup.GameSettings) .SetHeader(true) diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index c3542112a..5ebcbf798 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -658,7 +658,7 @@ internal static class ChatCommands HudManagerStartPatch.TryResizeUI(scale); } - private static void SelectCommand(PlayerControl player, string text, string[] args) + public static void SelectCommand(PlayerControl player, string text, string[] args) { if (Starspawn.IsDayBreak) return; @@ -900,7 +900,7 @@ internal static class ChatCommands } } - private static void ChooseCommand(PlayerControl player, string text, string[] args) + public static void ChooseCommand(PlayerControl player, string text, string[] args) { if (!Main.PlayerStates.TryGetValue(player.PlayerId, out var state) || state.IsDead || state.Role is not Pawn pawn) return; @@ -916,7 +916,7 @@ internal static class ChatCommands MeetingManager.SendCommandUsedMessage(args[0]); } - private static void ForgeCommand(PlayerControl player, string text, string[] args) + public static void ForgeCommand(PlayerControl player, string text, string[] args) { if (Starspawn.IsDayBreak) return; @@ -1024,7 +1024,7 @@ internal static class ChatCommands return; } - Utils.SendMessage(GetString($"8BallResponse.{IRandom.Instance.Next(Options.EightballCommandIndexes.GetInt())}"), player.IsAlive() ? byte.MaxValue : player.PlayerId, GetString("8BallResponseTitle")); + Utils.SendMessage(GetString($"8BallResponse.{IRandom.Instance.Next(20)}"), player.IsAlive() ? byte.MaxValue : player.PlayerId, GetString("8BallResponseTitle")); } public static void GameModePollCommand(PlayerControl player, string text, string[] args) @@ -2194,7 +2194,7 @@ internal static class ChatCommands AmongUsClient.Instance.KickPlayer(kickedPlayer.OwnerId, args[0] == "/ban"); } - private static void CheckCommand(PlayerControl player, string text, string[] args) + public static void CheckCommand(PlayerControl player, string text, string[] args) { if (Starspawn.IsDayBreak) return; diff --git a/Patches/HudSpritePatch.cs b/Patches/HudSpritePatch.cs index c6178053b..3de72dae3 100644 --- a/Patches/HudSpritePatch.cs +++ b/Patches/HudSpritePatch.cs @@ -33,7 +33,7 @@ public static class HudSpritePatch PlayerControl player = PlayerControl.LocalPlayer; if (!player) return; - if (!Main.EnableCustomButton.Value || !Main.ProcessShapeshifts || Mastermind.ManipulatedPlayers.ContainsKey(player.PlayerId) || ExileController.Instance || GameStates.IsMeeting) return; + if (!Main.EnableCustomButton.Value || Mastermind.ManipulatedPlayers.ContainsKey(player.PlayerId) || ExileController.Instance) return; if (!SetHudActivePatch.IsActive && !MeetingStates.FirstMeeting) return; if (!AmongUsClient.Instance.IsGameStarted || !Main.IntroDestroyed || GameStates.IsLobby || GameStates.IsNotJoined || !GameStates.InGame || IntroCutsceneDestroyPatch.PreventKill) return; @@ -51,11 +51,130 @@ public static class HudSpritePatch { if (!GhostRolesManager.AssignedGhostRoles.TryGetValue(player.PlayerId, out (CustomRoles Role, IGhostRole Instance) ghostRole)) return; if (!GhostRolesWithSprites.Contains(ghostRole.Role)) return; - + newAbilityButton = CustomButton.Get(ghostRole.Role.ToString()); goto Skip; } + if (GameStates.IsMeeting) + { + if (player.UsesMeetingShapeshift()) + { + switch (player.GetCustomRole()) + { + case CustomRoles.Starspawn: + { + newAbilityButton = CustomButton.Get("StarspawnShift"); + break; + } + case CustomRoles.Loner: + { + newAbilityButton = CustomButton.Get("Sidekick"); + break; + } + case CustomRoles.Exorcist: // temp + { + newAbilityButton = CustomButton.Get("Assassinate"); + break; + } + case CustomRoles.Ventriloquist: + { + newAbilityButton = CustomButton.Get("Hack"); + break; + } + case CustomRoles.Cleanser: + { + newAbilityButton = CustomButton.Get("Drink"); + break; + } + case CustomRoles.Clerk: // temp + { + newAbilityButton = CustomButton.Get("Clerk"); + break; + } + case CustomRoles.Godfather: + { + newAbilityButton = CustomButton.Get("EvilNearby"); + break; + } + case CustomRoles.EvilEraser: // temp + case CustomRoles.NiceEraser: + { + newAbilityButton = CustomButton.Get("Erase"); + break; + } + case CustomRoles.Councillor: + { + newAbilityButton = CustomButton.Get("Assassinate"); + break; + } + case CustomRoles.Negotiator: // temp + { + newAbilityButton = CustomButton.Get("Attack"); + break; + } + case CustomRoles.Swapper: + { + newAbilityButton = CustomButton.Get("PetToSwap"); + break; + } + case CustomRoles.Tether: + { + newAbilityButton = CustomButton.Get("Track"); + break; + } + case CustomRoles.Ricochet: // temp + { + newAbilityButton = CustomButton.Get("Shield"); + break; + } + case CustomRoles.President: + case CustomRoles.Retributionist: + { + newAbilityButton = CustomButton.Get("Kill"); + break; + } + case CustomRoles.Judge: + { + newAbilityButton = CustomButton.Get("JudgeIcon"); + break; + } + case CustomRoles.Socialite: // temp + { + newAbilityButton = CustomButton.Get("Bestower"); + break; + } + case CustomRoles.Soothsayer: + case CustomRoles.Oracle: + case CustomRoles.Markseeker: + case CustomRoles.FortuneTeller: + { + newAbilityButton = CustomButton.Get("prophecies"); + break; + } + case CustomRoles.Scout: + case CustomRoles.Captain: + { + newAbilityButton = CustomButton.Get("Track"); + break; + } + case CustomRoles.Inspector: + case CustomRoles.Inquisitor: // temp + { + newAbilityButton = CustomButton.Get("InspectorIcon"); + break; + } + case CustomRoles.Empress: + { + newAbilityButton = CustomButton.Get("Facilitator"); + break; + } + } + goto Skip; + } + else return; + } + bool usesPetInsteadOfKill = player.UsesPetInsteadOfKill(); bool shapeshifting = player.IsShifted(); @@ -93,6 +212,12 @@ public static class HudSpritePatch { newAbilityButton = CustomButton.Get("Up"); newPetButton = CustomButton.Get("PetToSwap"); + newKillButton = CustomButton.Get("Wand"); + break; + } + case CustomRoles.Tar: + { + newPetButton = CustomButton.Get("Tar"); break; } case CustomRoles.Socialite: @@ -123,6 +248,13 @@ public static class HudSpritePatch else newVentButton = CustomButton.Get("PetToSwap"); break; } + case CustomRoles.Silencer: + case CustomRoles.Blackmailer: + { + if (Silencer.SilenceMode.GetValue() >= 1 && player.Is(CustomRoles.Silencer)) newAbilityButton = CustomButton.Get("Blackmail"); + else newKillButton = CustomButton.Get("Blackmail"); + break; + } case CustomRoles.Vulture: { newReportButton = CustomButton.Get("Eat"); @@ -690,7 +822,7 @@ public static class HudSpritePatch case CustomRoles.Swooper: case CustomRoles.Wraith: { - if (Options.UsePhantomBasis.GetBool()) newAbilityButton = CustomButton.Get("Swoop"); + if (Options.UsePhantomBasis.GetBool()) newAbilityButton = CustomButton.Get("invisible"); else if (Options.UsePets.GetBool()) newPetButton = CustomButton.Get("invisible"); else newVentButton = CustomButton.Get("invisible"); break; @@ -735,7 +867,7 @@ public static class HudSpritePatch } default: { - if (ForceUpdate || usesPetInsteadOfKill) break; + if (player.Is(CustomRoles.Sleuth) || player.Is(CustomRoles.Bloodlust) || ForceUpdate || usesPetInsteadOfKill) break; SetButtonColors(); return; } @@ -745,13 +877,16 @@ public static class HudSpritePatch newPetButton = newKillButton; // shows default pet button if the ability can't be used yet due to cooldowns or if they no longer have uses left - if (player.HasAbilityCD() || player.GetAbilityUseLimit() < 1) // conditions with float.NaN always evaluate to false, which is good in this case + if (!Options.UsePets.GetBool() || player.HasAbilityCD() || player.GetAbilityUseLimit() < 1) // conditions with float.NaN always evaluate to false, which is good in this case newPetButton = DefaultIcons[4]; // for Bloodlust, due to it using the impostor vent button instead of the engineer vent button, show it on the vent button instead of the ability button, and only if the ability button is not the default button - if (Main.PlayerStates[player.PlayerId].SubRoles.Contains(CustomRoles.Bloodlust) && newAbilityButton != DefaultIcons[1] && !player.Is(CustomRoles.Scanner) && !player.Is(CustomRoles.Transporter)) + if (player.Is(CustomRoles.Bloodlust) && newAbilityButton != DefaultIcons[1] && !player.Is(CustomRoles.Scanner) && !player.Is(CustomRoles.Transporter)) newVentButton = newAbilityButton; + if (player.Is(CustomRoles.Sleuth) && newReportButton == DefaultIcons[5]) + newReportButton = CustomButton.Get("ExamineBody"); + Skip: SetButtonColors(); diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index f0bab2337..86e04c3b3 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -1182,6 +1182,7 @@ internal static class MeetingHudStartPatch // ------------------------------------------------------------------------------------------- CovenBase.CovenMeetingStartPatch.Postfix(); + GuessManager.StartMeetingPatch.Postfix(__instance); Inspector.StartMeetingPatch.Postfix(__instance); Judge.StartMeetingPatch.Postfix(__instance); @@ -1192,6 +1193,13 @@ internal static class MeetingHudStartPatch Retributionist.StartMeetingPatch.Postfix(__instance); Starspawn.StartMeetingPatch.Postfix(__instance); Ventriloquist.StartMeetingPatch.Postfix(__instance); + Exorcist.StartMeetingPatch.Postfix(__instance); + Summoner.StartMeetingPatch.Postfix(__instance); + Loner.StartMeetingPatch.Postfix(__instance); + Forger.StartMeetingPatch.Postfix(__instance); + Inquirer.StartMeetingPatch.Postfix(__instance); + Pawn.StartMeetingPatch.Postfix(__instance); + ShowHostMeetingPatch.Setup_Postfix(__instance); Crowded.MeetingHudStartPatch.Postfix(__instance); diff --git a/Resources/Images/Skills/Blackmail.png b/Resources/Images/Skills/Blackmail.png new file mode 100644 index 000000000..92a43bb93 Binary files /dev/null and b/Resources/Images/Skills/Blackmail.png differ diff --git a/Resources/Images/Skills/Clerk.png b/Resources/Images/Skills/Clerk.png new file mode 100644 index 000000000..bf5c2cf4c Binary files /dev/null and b/Resources/Images/Skills/Clerk.png differ diff --git a/Resources/Images/Skills/Erase.png b/Resources/Images/Skills/Erase.png new file mode 100644 index 000000000..36aac4539 Binary files /dev/null and b/Resources/Images/Skills/Erase.png differ diff --git a/Resources/Images/Skills/ExorcistIcon.png b/Resources/Images/Skills/ExorcistIcon.png new file mode 100644 index 000000000..e03a51c88 Binary files /dev/null and b/Resources/Images/Skills/ExorcistIcon.png differ diff --git a/Resources/Images/Skills/ForgerIcon.png b/Resources/Images/Skills/ForgerIcon.png new file mode 100644 index 000000000..129c45a21 Binary files /dev/null and b/Resources/Images/Skills/ForgerIcon.png differ diff --git a/Resources/Images/Skills/Imitate.png b/Resources/Images/Skills/Imitate.png new file mode 100644 index 000000000..e0fd73525 Binary files /dev/null and b/Resources/Images/Skills/Imitate.png differ diff --git a/Resources/Images/Skills/PawnPromotion.png b/Resources/Images/Skills/PawnPromotion.png new file mode 100644 index 000000000..eb4026a3f Binary files /dev/null and b/Resources/Images/Skills/PawnPromotion.png differ diff --git a/Resources/Images/Skills/StarspawnShift.png b/Resources/Images/Skills/StarspawnShift.png new file mode 100644 index 000000000..4fca35701 Binary files /dev/null and b/Resources/Images/Skills/StarspawnShift.png differ diff --git a/Resources/Images/Skills/Summon.png b/Resources/Images/Skills/Summon.png new file mode 100644 index 000000000..cc9057962 Binary files /dev/null and b/Resources/Images/Skills/Summon.png differ diff --git a/Resources/Images/Skills/Tar.png b/Resources/Images/Skills/Tar.png new file mode 100644 index 000000000..db7506718 Binary files /dev/null and b/Resources/Images/Skills/Tar.png differ diff --git a/Resources/Images/Skills/Up.png b/Resources/Images/Skills/Up.png index def6625f5..dd6fe0c48 100644 Binary files a/Resources/Images/Skills/Up.png and b/Resources/Images/Skills/Up.png differ diff --git a/Resources/Images/Skills/Wand.png b/Resources/Images/Skills/Wand.png new file mode 100644 index 000000000..a0b829ab5 Binary files /dev/null and b/Resources/Images/Skills/Wand.png differ diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index a14471ab2..412471e35 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -8366,87 +8366,7 @@ "8BallResponse.17": "My sources say no.", "8BallResponse.18": "Outlook not so good.", "8BallResponse.19": "Very doubtful.", - - "8BallResponse.20": "\\n", - "8BallResponse.21": "\\n", - "8BallResponse.22": "\\n", - "8BallResponse.23": "\\n", - "8BallResponse.24": "\\n", - "8BallResponse.25": "\\n", - "8BallResponse.26": "\\n", - "8BallResponse.27": "\\n", - "8BallResponse.28": "\\n", - "8BallResponse.29": "\\n", - "8BallResponse.30": "\\n", - "8BallResponse.31": "\\n", - "8BallResponse.32": "\\n", - "8BallResponse.33": "\\n", - "8BallResponse.34": "\\n", - "8BallResponse.35": "\\n", - "8BallResponse.36": "\\n", - "8BallResponse.37": "\\n", - "8BallResponse.38": "\\n", - "8BallResponse.39": "\\n", - "8BallResponse.40": "\\n", - "8BallResponse.41": "\\n", - "8BallResponse.42": "\\n", - "8BallResponse.43": "\\n", - "8BallResponse.44": "\\n", - "8BallResponse.45": "\\n", - "8BallResponse.46": "\\n", - "8BallResponse.47": "\\n", - "8BallResponse.48": "\\n", - "8BallResponse.49": "\\n", - "8BallResponse.50": "\\n", - "8BallResponse.51": "\\n", - "8BallResponse.52": "\\n", - "8BallResponse.53": "\\n", - "8BallResponse.54": "\\n", - "8BallResponse.55": "\\n", - "8BallResponse.56": "\\n", - "8BallResponse.57": "\\n", - "8BallResponse.58": "\\n", - "8BallResponse.59": "\\n", - "8BallResponse.60": "\\n", - "8BallResponse.61": "\\n", - "8BallResponse.62": "\\n", - "8BallResponse.63": "\\n", - "8BallResponse.64": "\\n", - "8BallResponse.65": "\\n", - "8BallResponse.66": "\\n", - "8BallResponse.67": "\\n", - "8BallResponse.68": "\\n", - "8BallResponse.69": "\\n", - "8BallResponse.70": "\\n", - "8BallResponse.71": "\\n", - "8BallResponse.72": "\\n", - "8BallResponse.73": "\\n", - "8BallResponse.74": "\\n", - "8BallResponse.75": "\\n", - "8BallResponse.76": "\\n", - "8BallResponse.77": "\\n", - "8BallResponse.78": "\\n", - "8BallResponse.79": "\\n", - "8BallResponse.80": "\\n", - "8BallResponse.81": "\\n", - "8BallResponse.82": "\\n", - "8BallResponse.83": "\\n", - "8BallResponse.84": "\\n", - "8BallResponse.85": "\\n", - "8BallResponse.86": "\\n", - "8BallResponse.87": "\\n", - "8BallResponse.88": "\\n", - "8BallResponse.89": "\\n", - "8BallResponse.90": "\\n", - "8BallResponse.91": "\\n", - "8BallResponse.92": "\\n", - "8BallResponse.93": "\\n", - "8BallResponse.94": "\\n", - "8BallResponse.95": "\\n", - "8BallResponse.96": "\\n", - "8BallResponse.97": "\\n", - "8BallResponse.98": "\\n", - "8BallResponse.99": "\\n", + "AAWarning": "<#ffff00>You must move away from this device or you die!", "Admin": "Admin", "AdminTag": "<#ff0000>Admin", @@ -9060,7 +8980,6 @@ "AnagramDiff.Medium": "Medium", "AnagramDiff.MediumHard": "Medium-Hard", "AnagramDiff.Hard": "Hard", - "EightballCommandIndexes": "Number of responses for /8ball command (Use the custom translate file to import additional responses. These responses will return blank if no definitions are made)", "MenuTitle.Other": "★ Different ★", "LadderDeath": "Fall From Ladders", "LadderDeathChance": "Fall To Death Chance", diff --git a/Roles/Standard/Coven/Summoner.cs b/Roles/Standard/Coven/Summoner.cs index 968a4ae7b..8ec73fa9a 100644 --- a/Roles/Standard/Coven/Summoner.cs +++ b/Roles/Standard/Coven/Summoner.cs @@ -4,6 +4,7 @@ using AmongUs.GameOptions; using EHR.Modules; using EHR.Modules.Extensions; using Hazel; +using UnityEngine; namespace EHR.Roles; @@ -262,4 +263,47 @@ public class Summoner : CovenBase if (seer.PlayerId == SummonerId) return string.Format(Translator.GetString("Summoner.SelfSuffix"), SummonedPlayerId.ColoredPlayerName(), (int)SummonedPlayerTimer.Remaining.TotalSeconds); return seer.PlayerId == SummonedPlayerId ? string.Format(Translator.GetString("Summoner.SummonedPlayerSuffix"), SummonerId.ColoredPlayerName(), CustomRoles.Summoner.ToColoredString(), (int)SummonedPlayerTimer.Remaining.TotalSeconds) : string.Empty; } + + private static void SummonerOnClick(byte playerId /*, MeetingHud __instance*/) + { + Logger.Msg($"Click: ID {playerId}", "Summoner UI"); + PlayerControl pc = Utils.GetPlayerById(playerId); + if (pc == null || pc.IsAlive() || !GameStates.IsVoting || Starspawn.IsDayBreak) return; + + var command = $"/summon {playerId}"; + + if (AmongUsClient.Instance.AmHost) + ChatCommands.SummonCommand(PlayerControl.LocalPlayer, command, command.Split(' ')); + else + ChatCommands.RequestCommandProcessingFromHost(command, "Summon"); + } + + private static void CreateSummonerButton(MeetingHud __instance) + { + foreach (PlayerVoteArea pva in __instance.playerStates) + { + PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + if (!pc || pc.IsAlive()) continue; + + GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; + GameObject targetBox = Object.Instantiate(template, pva.transform); + targetBox.name = "SummonerButton"; + targetBox.transform.localPosition = new(-0.35f, 0.03f, -1.31f); + var renderer = targetBox.GetComponent(); + renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Summon.png", 130f); + var button = targetBox.GetComponent(); + button.OnClick.RemoveAllListeners(); + button.OnClick.AddListener((Action)(() => SummonerOnClick(pva.TargetPlayerId))); + } + } + + //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] + public static class StartMeetingPatch + { + public static void Postfix(MeetingHud __instance) + { + if (PlayerControl.LocalPlayer.IsAlive() && PlayerControl.LocalPlayer.Is(CustomRoles.Summoner)) + CreateSummonerButton(__instance); + } + } } \ No newline at end of file diff --git a/Roles/Standard/Crewmate/Investigate/Imitator.cs b/Roles/Standard/Crewmate/Investigate/Imitator.cs index 8c3753558..870bfc792 100644 --- a/Roles/Standard/Crewmate/Investigate/Imitator.cs +++ b/Roles/Standard/Crewmate/Investigate/Imitator.cs @@ -91,7 +91,7 @@ public class Imitator : RoleBase targetBox.name = "ImitatorButton"; targetBox.transform.localPosition = new(-0.35f, 0.03f, -1.31f); var renderer = targetBox.GetComponent(); - renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.TargetIcon.png", 130f); + renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Imitate.png", 130f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); button.OnClick.AddListener((Action)(() => ImitatorOnClick(pva.TargetPlayerId))); diff --git a/Roles/Standard/Crewmate/Investigate/Inquirer.cs b/Roles/Standard/Crewmate/Investigate/Inquirer.cs index 287b0c4ca..33da2997b 100644 --- a/Roles/Standard/Crewmate/Investigate/Inquirer.cs +++ b/Roles/Standard/Crewmate/Investigate/Inquirer.cs @@ -1,4 +1,9 @@ -namespace EHR.Roles; +using System; +using EHR.Modules; +using UnityEngine; +using static EHR.Translator; + +namespace EHR.Roles; public class Inquirer : RoleBase { @@ -36,4 +41,46 @@ public class Inquirer : RoleBase { playerId.SetAbilityUseLimit(AbilityUseLimit.GetFloat()); } + + public static void CreateInquirerButton(MeetingHud __instance) + { + foreach (PlayerVoteArea pva in __instance.playerStates) + { + PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + if (!pc || !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.35f, 0.03f, -1.31f); + var renderer = targetBox.GetComponent(); + renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.InspectorIcon.png", 160f); + var button = targetBox.GetComponent(); + button.OnClick.RemoveAllListeners(); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.TargetPlayerId, __instance, true))); + } + } + + //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] + public static class StartMeetingPatch + { + public static void Postfix(MeetingHud __instance) + { + if (PlayerControl.LocalPlayer.Is(CustomRoles.Inquirer) && PlayerControl.LocalPlayer.IsAlive()) + CreateInquirerButton(__instance); + } + } + + public static void ProcessGuesserUI(byte playerId, CustomRoles role) + { + PlayerControl pc = Utils.GetPlayerById(playerId); + if (pc == null || !pc.IsAlive() || Starspawn.IsDayBreak) return; + + var command = $"/check {playerId} {GetString(role.ToString())}"; + + if (AmongUsClient.Instance.AmHost) + ChatCommands.CheckCommand(PlayerControl.LocalPlayer, command, command.Split(' ')); + else + ChatCommands.RequestCommandProcessingFromHost(command, "Check"); + } } \ No newline at end of file diff --git a/Roles/Standard/Impostor/Concealing/Forger.cs b/Roles/Standard/Impostor/Concealing/Forger.cs index f050efe30..463c46009 100644 --- a/Roles/Standard/Impostor/Concealing/Forger.cs +++ b/Roles/Standard/Impostor/Concealing/Forger.cs @@ -1,4 +1,7 @@ using System.Collections.Generic; +using System; +using UnityEngine; +using static EHR.Translator; namespace EHR.Roles; @@ -31,4 +34,46 @@ public class Forger : RoleBase On = true; playerId.SetAbilityUseLimit(AbilityUseLimit.GetFloat()); } + + public static void CreateForgerButton(MeetingHud __instance) + { + foreach (PlayerVoteArea pva in __instance.playerStates) + { + PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + if (!pc || !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.35f, 0.03f, -1.31f); + var renderer = targetBox.GetComponent(); + renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.ForgerIcon.png", 160f); + var button = targetBox.GetComponent(); + button.OnClick.RemoveAllListeners(); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.TargetPlayerId, __instance, true))); + } + } + + //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] + public static class StartMeetingPatch + { + public static void Postfix(MeetingHud __instance) + { + if (PlayerControl.LocalPlayer.Is(CustomRoles.Forger) && PlayerControl.LocalPlayer.IsAlive()) + CreateForgerButton(__instance); + } + } + + public static void ProcessGuesserUI(byte playerId, CustomRoles role) + { + PlayerControl pc = Utils.GetPlayerById(playerId); + if (pc == null || !pc.IsAlive() || Starspawn.IsDayBreak) return; + + var command = $"/forge {playerId} {GetString(role.ToString())}"; + + if (AmongUsClient.Instance.AmHost) + ChatCommands.ForgeCommand(PlayerControl.LocalPlayer, command, command.Split(' ')); + else + ChatCommands.RequestCommandProcessingFromHost(command, "Forge"); + } } \ No newline at end of file diff --git a/Roles/Standard/Impostor/Miscellaneous/Exorcist.cs b/Roles/Standard/Impostor/Miscellaneous/Exorcist.cs index 89096736f..5a8d81c8c 100644 --- a/Roles/Standard/Impostor/Miscellaneous/Exorcist.cs +++ b/Roles/Standard/Impostor/Miscellaneous/Exorcist.cs @@ -1,4 +1,8 @@ -namespace EHR.Roles; +using System; +using TMPro; +using UnityEngine; + +namespace EHR.Roles; public class Exorcist : RoleBase { @@ -37,4 +41,54 @@ public class Exorcist : RoleBase const string command = "/exo"; ChatCommands.ExoCommand(shapeshifter, command, command.Split(' ')); } + + private static void ExorcistOnClick(GameObject exorcistButton) + { + Logger.Msg($"Exorcist Click: ID {PlayerControl.LocalPlayer.PlayerId}", "Exorcist UI"); + if (PlayerControl.LocalPlayer == null || !PlayerControl.LocalPlayer.IsAlive() || !GameStates.IsVoting) return; + + const string command = "/exo"; + + if (AmongUsClient.Instance.AmHost) + ChatCommands.ExoCommand(PlayerControl.LocalPlayer, command, command.Split(' ')); + else + ChatCommands.RequestCommandProcessingFromHost(command, "Exo"); + + exorcistButton.SetActive(false); + LateTask.New(() => exorcistButton.SetActive(true), 1f, "ExorcistButton"); + } + + private static void CreateExorcistButton(MeetingHud __instance) + { + GameObject existingButton = GameObject.Find("ExorcistButton"); + if (existingButton) Object.Destroy(existingButton.gameObject); + if (!PlayerControl.LocalPlayer || !PlayerControl.LocalPlayer.IsAlive()) return; + + GameObject parent = GameObject.Find("Main Camera").transform.Find("Hud").Find("ChatUi").Find("ChatScreenRoot").Find("ChatScreenContainer").gameObject; + GameObject template = __instance.transform.Find("MeetingContents").Find("ButtonStuff").Find("button_skipVoting").gameObject; + GameObject exorcistButton = Object.Instantiate(template, parent.transform); + exorcistButton.name = "ExorcistButton"; + exorcistButton.transform.localPosition = new(3.46f, 0f, 45f); + exorcistButton.SetActive(true); + var renderer = exorcistButton.GetComponent(); + renderer.sprite = CustomButton.Get("ExorcistIcon"); + renderer.color = Color.white; + GameObject Text_TMP = exorcistButton.GetComponentInChildren().gameObject; + Text_TMP.SetActive(false); + var button = exorcistButton.GetComponent(); + button.OnClick.RemoveAllListeners(); + button.OnClick.AddListener((Action)(() => ExorcistOnClick(exorcistButton))); + GameObject ControllerHighlight = exorcistButton.transform.Find("ControllerHighlight").gameObject; + ControllerHighlight.transform.localScale = new(0.5f, 2f, 0.5f); + } + + //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] + public static class StartMeetingPatch + { + public static void Postfix(MeetingHud __instance) + { + if (PlayerControl.LocalPlayer.IsAlive() && PlayerControl.LocalPlayer.Is(CustomRoles.Exorcist)) + CreateExorcistButton(__instance); + } + } } \ No newline at end of file diff --git a/Roles/Standard/Impostor/Miscellaneous/Loner.cs b/Roles/Standard/Impostor/Miscellaneous/Loner.cs index c155cfb35..f227de457 100644 --- a/Roles/Standard/Impostor/Miscellaneous/Loner.cs +++ b/Roles/Standard/Impostor/Miscellaneous/Loner.cs @@ -1,5 +1,8 @@ -using System.Linq; +using System; +using System.Linq; using EHR.Modules; +using UnityEngine; +using static EHR.Translator; namespace EHR.Roles; @@ -46,7 +49,7 @@ public class Loner : RoleBase public override void AfterMeetingTasks() { var pc = PickedPlayer.GetPlayer(); - + if (!Done && PickedPlayer != byte.MaxValue && PickedRole != CustomRoles.Crewmate && pc != null) { Done = true; @@ -54,4 +57,46 @@ public class Loner : RoleBase pc.RpcChangeRoleBasis(PickedRole); } } + + public static void CreateLonerButton(MeetingHud __instance) + { + foreach (PlayerVoteArea pva in __instance.playerStates) + { + PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + if (!pc || !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.35f, 0.03f, -1.31f); + var renderer = targetBox.GetComponent(); + renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Sidekick.png", 160f); + var button = targetBox.GetComponent(); + button.OnClick.RemoveAllListeners(); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(pva.TargetPlayerId, __instance, true))); + } + } + + //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] + public static class StartMeetingPatch + { + public static void Postfix(MeetingHud __instance) + { + if (PlayerControl.LocalPlayer.Is(CustomRoles.Loner) && PlayerControl.LocalPlayer.IsAlive()) + CreateLonerButton(__instance); + } + } + + public static void ProcessGuesserUI(byte playerId, CustomRoles role) + { + PlayerControl pc = Utils.GetPlayerById(playerId); + if (pc == null || !pc.IsAlive() || Starspawn.IsDayBreak) return; + + var command = $"/select {playerId} {GetString(role.ToString())}"; + + if (AmongUsClient.Instance.AmHost) + ChatCommands.SelectCommand(PlayerControl.LocalPlayer, command, command.Split(' ')); + else + ChatCommands.RequestCommandProcessingFromHost(command, "Select"); + } } \ No newline at end of file diff --git a/Roles/Standard/Impostor/Support/Ventriloquist.cs b/Roles/Standard/Impostor/Support/Ventriloquist.cs index 2c3779033..cfc229a5e 100644 --- a/Roles/Standard/Impostor/Support/Ventriloquist.cs +++ b/Roles/Standard/Impostor/Support/Ventriloquist.cs @@ -44,12 +44,12 @@ public class Ventriloquist : RoleBase ChatCommands.TargetCommand(shapeshifter, command, command.Split(' ')); } - private static void VentriloquisttOnClick(byte playerId /*, MeetingHud __instance*/) + private static void VentriloquistOnClick(byte playerId /*, MeetingHud __instance*/) { Logger.Msg($"Click: ID {playerId}", "Ventriloquist UI"); PlayerControl pc = Utils.GetPlayerById(playerId); if (pc == null || !pc.IsAlive() || !GameStates.IsVoting || Starspawn.IsDayBreak) return; - + var command = $"/target {playerId}"; if (AmongUsClient.Instance.AmHost) @@ -73,7 +73,7 @@ public class Ventriloquist : RoleBase renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.Hack.png", 160f); var button = targetBox.GetComponent(); button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => VentriloquisttOnClick(pva.TargetPlayerId))); + button.OnClick.AddListener((Action)(() => VentriloquistOnClick(pva.TargetPlayerId))); } } diff --git a/Roles/Standard/Neutral/Benign/Pawn.cs b/Roles/Standard/Neutral/Benign/Pawn.cs index 13fbf1ef4..6baa5edc3 100644 --- a/Roles/Standard/Neutral/Benign/Pawn.cs +++ b/Roles/Standard/Neutral/Benign/Pawn.cs @@ -1,4 +1,8 @@ -using EHR.Modules; +using System.Linq; +using EHR.Modules; +using System; +using UnityEngine; +using static EHR.Translator; namespace EHR.Roles; @@ -48,13 +52,54 @@ public class Pawn : RoleBase { var pc = PawnId.GetPlayer(); if (pc == null || !pc.IsAlive()) return; - + if (!pc.AllTasksCompleted() || ChosenRole == CustomRoles.NotAssigned || ChosenRole.IsAdditionRole() || ChosenRole.IsForOtherGameMode()) return; pc.RpcSetCustomRole(ChosenRole); pc.RpcChangeRoleBasis(ChosenRole); - + if (pc.AmOwner && ChosenRole is CustomRoles.Crewmate or CustomRoles.CrewmateEHR) Achievements.Type.Why.Complete(); } + + public static void CreatePawnButton(MeetingHud __instance) + { + PlayerVoteArea localPva = __instance.playerStates + .FirstOrDefault(pva => pva.TargetPlayerId == PlayerControl.LocalPlayer.PlayerId); + + PlayerControl pc = Utils.GetPlayerById(localPva.TargetPlayerId); + if (!pc || !pc.IsAlive()) return; + + GameObject template = localPva.Buttons.transform.Find("CancelButton").gameObject; + GameObject targetBox = Object.Instantiate(template, localPva.transform); + targetBox.name = "ShootButton"; + targetBox.transform.localPosition = new(-0.35f, 0.03f, -1.31f); + var renderer = targetBox.GetComponent(); + renderer.sprite = Utils.LoadSprite("EHR.Resources.Images.Skills.PawnPromotion.png", 160f); + var button = targetBox.GetComponent(); + button.OnClick.RemoveAllListeners(); + button.OnClick.AddListener((Action)(() => GuessManager.GuesserOnClick(localPva.TargetPlayerId, __instance, true))); + } + + //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] + public static class StartMeetingPatch + { + public static void Postfix(MeetingHud __instance) + { + if (PlayerControl.LocalPlayer.Is(CustomRoles.Pawn) && PlayerControl.LocalPlayer.IsAlive()) + CreatePawnButton(__instance); + } + } + + public static void ProcessGuesserUI(CustomRoles role) + { + PlayerControl pc = PlayerControl.LocalPlayer; + + var command = $"/choose {GetString(role.ToString())}"; + + if (AmongUsClient.Instance.AmHost) + ChatCommands.ChooseCommand(PlayerControl.LocalPlayer, command, command.Split(' ')); + else + ChatCommands.RequestCommandProcessingFromHost(command, "Choose"); + } } \ No newline at end of file