From 93e7053405349884b05df33f8336a619cc0e25a1 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Sat, 25 May 2024 19:22:29 +0200 Subject: [PATCH] Add "Died First in Last Game" Warning, fix a few minor bugs --- GameMode/HnSManager.cs | 14 ++-- Modules/CustomNetObject.cs | 24 +++++- Modules/Utils.cs | 3 + Patches/ControlPatch.cs | 2 +- Patches/CreateGameOptionsPatches.cs | 110 ++++++++++++++-------------- Patches/MeetingHudPatch.cs | 1 - Patches/OnGameStartedPatch.cs | 4 +- Patches/PlayerControlPatch.cs | 15 ++-- Patches/PlayerJoinAndLeftPatch.cs | 4 +- Resources/Lang/en_US.json | 1 + Roles/RoleBase.cs | 2 +- main.cs | 5 +- 12 files changed, 103 insertions(+), 82 deletions(-) diff --git a/GameMode/HnSManager.cs b/GameMode/HnSManager.cs index fe52acedc..f3d349733 100644 --- a/GameMode/HnSManager.cs +++ b/GameMode/HnSManager.cs @@ -58,7 +58,7 @@ namespace EHR public static void Init() { - TimeLeft = MaxGameLength.GetInt() + 8; + TimeLeft = MaxGameLength.GetInt(); LastUpdate = Utils.TimeStamp; Type[] types = GetAllHnsRoleTypes(); @@ -114,6 +114,7 @@ namespace EHR { Dictionary result = []; List allPlayers = [.. Main.AllAlivePlayerControls]; + if (Main.GM.Value) allPlayers.RemoveAll(x => x.IsHost()); allPlayers = allPlayers.Shuffle(); Dictionary memberNum = new() @@ -328,10 +329,9 @@ namespace EHR return true; } - // If time is up, the game is over and crewmates win - if (TimeLeft <= 0) + // If time is up or there are no impostors in the game, the game is over and crewmates win + if (TimeLeft <= 0 || PlayerRoles.Values.All(x => x.Interface.Team != Team.Impostor)) { - reason = GameOverReason.HumansByTask; SetWinners(CustomWinner.Hider, Team.Crewmate); return true; } @@ -409,7 +409,7 @@ namespace EHR { public static void Postfix(PlayerControl __instance) { - if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.HideAndSeek) return; + if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.HideAndSeek || Main.HasJustStarted) return; long now = Utils.TimeStamp; if (LastUpdate == now) return; @@ -417,14 +417,14 @@ namespace EHR TimeLeft--; - if (DangerMeter.GetBool() || (TimeLeft + 1) % 60 == 0 || TimeLeft <= 60) Utils.NotifyRoles(); - PlayerRoles = PlayerRoles.Where(x => Utils.GetPlayerById(x.Key) != null).ToDictionary(x => x.Key, x => x.Value); var imps = PlayerRoles.Where(x => x.Value.Interface.Team == Team.Impostor).ToDictionary(x => x.Key, x => Utils.GetPlayerById(x.Key).Pos()); var nonImps = PlayerRoles.Where(x => x.Value.Interface.Team is Team.Crewmate or Team.Neutral).ToArray(); ClosestImpostor = nonImps.ToDictionary(x => x.Key, x => imps.MinBy(y => Vector2.Distance(y.Value, Utils.GetPlayerById(x.Key).Pos())).Key); Danger = nonImps.ToDictionary(x => x.Key, x => Math.Clamp(((1 + (int)Math.Ceiling(Vector2.Distance(Utils.GetPlayerById(x.Key).Pos(), Utils.GetPlayerById(ClosestImpostor[x.Key]).Pos()))) / 3) - 1, 0, 5)); + + if (DangerMeter.GetBool() || (TimeLeft + 1) % 60 == 0 || TimeLeft <= 60) Utils.NotifyRoles(); } } } diff --git a/Modules/CustomNetObject.cs b/Modules/CustomNetObject.cs index dfa25e18d..ffc803153 100644 --- a/Modules/CustomNetObject.cs +++ b/Modules/CustomNetObject.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using EHR.Roles.Crewmate; @@ -5,6 +6,7 @@ using HarmonyLib; using Hazel; using InnerNet; using UnityEngine; +using Object = UnityEngine.Object; // Credit: https://github.com/Rabek009/MoreGamemodes/blob/e054eb498094dfca0a365fc6b6fea8d17f9974d7/Modules/CustomObjects // Huge thanks to Rabek009 for this code! @@ -234,11 +236,25 @@ namespace EHR protected override void OnFixedUpdate() { - if (Gone) return; - if (SpawnTimeStamp + Tornado.TornadoDuration.GetInt() < Utils.TimeStamp) + try { - Gone = true; - Despawn(); + if (Gone) return; + if (SpawnTimeStamp + Tornado.TornadoDuration.GetInt() < Utils.TimeStamp) + { + Gone = true; + Despawn(); + } + } + catch (NullReferenceException) + { + try + { + Despawn(); + } + finally + { + Gone = true; + } } } } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 65c9d3ed7..82ca8174b 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -2300,6 +2300,9 @@ public static class Utils Main.PlayerStates.Values.Do(x => TargetSuffix.Append(x.Role.GetSuffix(seer, target, isMeeting: isForMeeting))); + if (Main.FirstDied != int.MaxValue && Main.FirstDied == target.GetClientId()) + TargetSuffix.Append(GetString("DiedR1Warning")); + string TargetDeathReason = string.Empty; if (seer.KnowDeathReason(target)) TargetDeathReason = $"\n({ColorString(GetRoleColor(CustomRoles.Doctor), GetVitalText(target.PlayerId))})"; diff --git a/Patches/ControlPatch.cs b/Patches/ControlPatch.cs index 49e28c48a..dd530c9a7 100644 --- a/Patches/ControlPatch.cs +++ b/Patches/ControlPatch.cs @@ -35,7 +35,7 @@ internal class ControllerManagerUpdatePatch } } - if (GetKeysDown(KeyCode.LeftShift, KeyCode.LeftControl, KeyCode.X) && Main.CurrentMap == MapNames.Airship) + if (GetKeysDown(KeyCode.LeftShift, KeyCode.LeftControl, KeyCode.X)) { ExileController.Instance?.ReEnableGameplay(); } diff --git a/Patches/CreateGameOptionsPatches.cs b/Patches/CreateGameOptionsPatches.cs index 1b83edf19..29c719773 100644 --- a/Patches/CreateGameOptionsPatches.cs +++ b/Patches/CreateGameOptionsPatches.cs @@ -11,72 +11,70 @@ namespace EHR.Patches internal static class CreateGameOptionsPatches { [HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.Awake))] - public static class CreateOptionsPicker_Awake + public static class CreateOptionsPickerAwakePatch { public static void Postfix(CreateOptionsPicker __instance) { if (__instance.mode != SettingsMode.Host) return; + var firstButtonRenderer = __instance.MaxPlayerButtons[0]; + firstButtonRenderer.GetComponentInChildren().text = "-"; + firstButtonRenderer.enabled = false; + + var firstButtonButton = firstButtonRenderer.GetComponent(); + firstButtonButton.OnClick.RemoveAllListeners(); + firstButtonButton.OnClick.AddListener((Action)(() => { - var firstButtonRenderer = __instance.MaxPlayerButtons[0]; - firstButtonRenderer.GetComponentInChildren().text = "-"; - firstButtonRenderer.enabled = false; - - var firstButtonButton = firstButtonRenderer.GetComponent(); - firstButtonButton.OnClick.RemoveAllListeners(); - firstButtonButton.OnClick.AddListener((Action)(() => - { - for (var i = 1; i < 11; i++) - { - var playerButton = __instance.MaxPlayerButtons[i]; - var tmp = playerButton.GetComponentInChildren(); - var newValue = Mathf.Max(byte.Parse(tmp.text) - 10, byte.Parse(playerButton.name) - 2); - tmp.text = newValue.ToString(); - } - - __instance.UpdateMaxPlayersButtons(__instance.GetTargetOptions()); - })); - - var lastButtonRenderer = __instance.MaxPlayerButtons[^1]; - lastButtonRenderer.GetComponentInChildren().text = "+"; - lastButtonRenderer.enabled = false; - - var lastButtonButton = lastButtonRenderer.GetComponent(); - lastButtonButton.OnClick.RemoveAllListeners(); - lastButtonButton.OnClick.AddListener((Action)(() => - { - for (var i = 1; i < 11; i++) - { - var playerButton = __instance.MaxPlayerButtons[i]; - var tmp = playerButton.GetComponentInChildren(); - var newValue = Mathf.Min(byte.Parse(tmp.text) + 10, - 127 - 14 + byte.Parse(playerButton.name)); - tmp.text = newValue.ToString(); - } - - __instance.UpdateMaxPlayersButtons(__instance.GetTargetOptions()); - })); - for (var i = 1; i < 11; i++) { - var playerButton = __instance.MaxPlayerButtons[i].GetComponent(); - var text = playerButton.GetComponentInChildren(); - - playerButton.OnClick.RemoveAllListeners(); - playerButton.OnClick.AddListener((Action)(() => - { - var maxPlayers = byte.Parse(text.text); - var maxImp = Mathf.Min(__instance.GetTargetOptions().NumImpostors, maxPlayers / 2); - __instance.GetTargetOptions().SetInt(Int32OptionNames.NumImpostors, maxImp); - __instance.ImpostorButtons[1].TextMesh.text = maxImp.ToString(); - __instance.SetMaxPlayersButtons(maxPlayers); - })); + var playerButton = __instance.MaxPlayerButtons[i]; + var tmp = playerButton.GetComponentInChildren(); + var newValue = Mathf.Max(byte.Parse(tmp.text) - 10, byte.Parse(playerButton.name) - 2); + tmp.text = newValue.ToString(); } - foreach (var button in __instance.MaxPlayerButtons) + __instance.UpdateMaxPlayersButtons(__instance.GetTargetOptions()); + })); + + var lastButtonRenderer = __instance.MaxPlayerButtons[^1]; + lastButtonRenderer.GetComponentInChildren().text = "+"; + lastButtonRenderer.enabled = false; + + var lastButtonButton = lastButtonRenderer.GetComponent(); + lastButtonButton.OnClick.RemoveAllListeners(); + lastButtonButton.OnClick.AddListener((Action)(() => + { + for (var i = 1; i < 11; i++) { - button.enabled = button.GetComponentInChildren().text == __instance.GetTargetOptions().MaxPlayers.ToString(); + var playerButton = __instance.MaxPlayerButtons[i]; + var tmp = playerButton.GetComponentInChildren(); + var newValue = Mathf.Min(byte.Parse(tmp.text) + 10, + 127 - 14 + byte.Parse(playerButton.name)); + tmp.text = newValue.ToString(); } + + __instance.UpdateMaxPlayersButtons(__instance.GetTargetOptions()); + })); + + for (var i = 1; i < 11; i++) + { + var playerButton = __instance.MaxPlayerButtons[i].GetComponent(); + var text = playerButton.GetComponentInChildren(); + + playerButton.OnClick.RemoveAllListeners(); + playerButton.OnClick.AddListener((Action)(() => + { + var maxPlayers = byte.Parse(text.text); + var maxImp = Mathf.Min(__instance.GetTargetOptions().NumImpostors, maxPlayers / 2); + __instance.GetTargetOptions().SetInt(Int32OptionNames.NumImpostors, maxImp); + __instance.ImpostorButtons[1].TextMesh.text = maxImp.ToString(); + __instance.SetMaxPlayersButtons(maxPlayers); + })); + } + + foreach (var button in __instance.MaxPlayerButtons) + { + button.enabled = button.GetComponentInChildren().text == __instance.GetTargetOptions().MaxPlayers.ToString(); } { @@ -124,7 +122,7 @@ namespace EHR.Patches } [HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.UpdateMaxPlayersButtons))] - public static class CreateOptionsPicker_UpdateMaxPlayersButtons + public static class CreateOptionsPickerUpdateMaxPlayersButtonsPatch { public static bool Prefix(CreateOptionsPicker __instance, [HarmonyArgument(0)] IGameOptions opts) { @@ -144,7 +142,7 @@ namespace EHR.Patches } [HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.UpdateImpostorsButtons))] - public static class CreateOptionsPicker_UpdateImpostorsButtons + public static class CreateOptionsPickerUpdateImpostorsButtonsPatch { public static bool Prefix() { diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index ee0499321..4983ae79d 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -348,7 +348,6 @@ class CheckForEndVotingPatch var exileId = exiledPlayer.PlayerId; if (exileId > 254) return; var realName = exiledPlayer.Object.GetRealName(isMeeting: true); - Main.LastVotedPlayer = realName; var player = Utils.GetPlayerById(exiledPlayer.PlayerId); var crole = exiledPlayer.GetCustomRole(); diff --git a/Patches/OnGameStartedPatch.cs b/Patches/OnGameStartedPatch.cs index 5a47884ef..27ac8c8f0 100644 --- a/Patches/OnGameStartedPatch.cs +++ b/Patches/OnGameStartedPatch.cs @@ -64,8 +64,8 @@ internal class ChangeRoleSettings Main.ClientIdList = []; Main.CheckShapeshift = []; Main.ShapeshiftTarget = []; - Main.ShieldPlayer = Options.ShieldPersonDiedFirst.GetBool() ? Main.FirstDied : byte.MaxValue; - Main.FirstDied = byte.MaxValue; + Main.ShieldPlayer = Options.ShieldPersonDiedFirst.GetBool() ? Main.FirstDied : int.MaxValue; + Main.FirstDied = int.MaxValue; Main.MadmateNum = 0; Mayor.MayorUsedButtonCount = []; diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index 6d3fd05f2..4b068320e 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -401,9 +401,9 @@ class CheckMurderPatch break; } - if (Main.ShieldPlayer != byte.MaxValue && Main.ShieldPlayer == target.PlayerId && IsAllAlive) + if (Main.ShieldPlayer != int.MaxValue && Main.ShieldPlayer == target.GetClientId() && IsAllAlive) { - Main.ShieldPlayer = byte.MaxValue; + Main.ShieldPlayer = int.MaxValue; killer.SetKillCooldown(15f); killer.Notify(GetString("TriedToKillLastGameFirstKill"), 10f); return false; @@ -485,16 +485,16 @@ class MurderPlayerPatch } // Let’s see if Youtuber was stabbed first - if (Main.FirstDied == byte.MaxValue && target.Is(CustomRoles.Youtuber)) + if (Main.FirstDied == int.MaxValue && target.Is(CustomRoles.Youtuber)) { CustomSoundsManager.RPCPlayCustomSoundAll("Congrats"); CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Youtuber); CustomWinnerHolder.WinnerIds.Add(target.PlayerId); } - // Record the first blow - if (Main.FirstDied == byte.MaxValue) - Main.FirstDied = target.PlayerId; + // Record the first death + if (Main.FirstDied == int.MaxValue) + Main.FirstDied = target.GetClientId(); Postman.CheckAndResetTargets(target, isDeath: true); @@ -1522,6 +1522,9 @@ class FixedUpdatePatch if (Options.CurrentGameMode == CustomGameMode.SoloKombat) Suffix.Append(SoloKombatManager.GetDisplayHealth(target)); + if (Main.FirstDied != int.MaxValue && Main.FirstDied == target.GetClientId() && !self) + Suffix.Append(GetString("DiedR1Warning")); + // Devourer if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.playerIdList.Any(x => Main.PlayerStates[x].Role is Devourer { IsEnable: true } dv && dv.PlayerSkinsCosumed.Contains(seer.PlayerId))) RealName = GetString("DevouredName"); diff --git a/Patches/PlayerJoinAndLeftPatch.cs b/Patches/PlayerJoinAndLeftPatch.cs index df364aaf5..df25c7bc4 100644 --- a/Patches/PlayerJoinAndLeftPatch.cs +++ b/Patches/PlayerJoinAndLeftPatch.cs @@ -133,9 +133,11 @@ class OnPlayerLeftPatch { if (GameStates.IsInGame) { + if (Options.CurrentGameMode == CustomGameMode.HideAndSeek) HnSManager.PlayerRoles.Remove(data.Character.PlayerId); + if (data.Character.Is(CustomRoles.Lovers) && !data.Character.Data.IsDead) { - foreach (var lovers in Main.LoversPlayers) + foreach (var lovers in Main.LoversPlayers.ToArray()) { Main.IsLoversDead = true; Main.LoversPlayers.Remove(lovers); diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index 3a1f659aa..1acf92356 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -1740,6 +1740,7 @@ "Alive": "Alive", "Win": " Wins!", "Last-": "Last ", + "DiedR1Warning": "<#ffff00>(Died First in Last Game)", "DeputyHandcuffCooldown": "Handcuff Cooldown", "DeputyHandcuffMax": "Maximum Handcuffs", "CanHandcuffSheriff": "Can Handcuff Sheriff", diff --git a/Roles/RoleBase.cs b/Roles/RoleBase.cs index bbf7c9abd..940ff04aa 100644 --- a/Roles/RoleBase.cs +++ b/Roles/RoleBase.cs @@ -171,7 +171,7 @@ namespace EHR public virtual bool KnowRole(PlayerControl seer, PlayerControl target) { - return false; + return seer.GetCustomRole() == target.GetCustomRole() && seer.GetTeam() == target.GetTeam(); } } } \ No newline at end of file diff --git a/main.cs b/main.cs index 06c7a7013..05bcecb04 100644 --- a/main.cs +++ b/main.cs @@ -71,7 +71,6 @@ public class Main : BasePlugin public static readonly Dictionary AbilityCD = []; public static Dictionary AbilityUseLimit = []; public static List DontCancelVoteList = []; - public static string LastVotedPlayer; public static byte NimblePlayer = byte.MaxValue; public static byte PhysicistPlayer = byte.MaxValue; public static byte BloodlustPlayer = byte.MaxValue; @@ -102,8 +101,8 @@ public class Main : BasePlugin public static float DefaultImpostorVision; public static readonly bool IsAprilFools = DateTime.Now.Month == 4 && DateTime.Now.Day is 1; public static bool ResetOptions = true; - public static byte FirstDied = byte.MaxValue; - public static byte ShieldPlayer = byte.MaxValue; + public static int FirstDied = int.MaxValue; + public static int ShieldPlayer = int.MaxValue; public static readonly List LoversPlayers = []; public static bool IsLoversDead = true;