From 30acb49fcb6bd747f82a26a65b38ac47df69bdb2 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Thu, 12 Jun 2025 09:36:45 +0200 Subject: [PATCH] new settings & fixes --- GameMode/NaturalDisasters.cs | 13 ++++++++++--- Modules/CustomRolesHelper.cs | 9 +++++++++ Modules/FixedUpdateCaller.cs | 11 +++++++---- Modules/GameState.cs | 2 +- Modules/OptionHolder.cs | 6 ++++++ Modules/OptionItem/OptionItem.cs | 16 ++++++++-------- Modules/OptionShower.cs | 3 +-- Modules/TemplateManager.cs | 5 ++--- Modules/Translator.cs | 5 ++--- Patches/AnnouncementPatch.cs | 1 - Patches/ChatCommandPatch.cs | 20 ++++++++++++++++---- Patches/GameOptionsMenuPatch.cs | 4 +++- Resources/Lang/en_US.json | 5 +++++ Roles/Neutral/Dealer.cs | 5 +++++ 14 files changed, 75 insertions(+), 30 deletions(-) diff --git a/GameMode/NaturalDisasters.cs b/GameMode/NaturalDisasters.cs index 006770e52..17fe0c333 100644 --- a/GameMode/NaturalDisasters.cs +++ b/GameMode/NaturalDisasters.cs @@ -118,7 +118,7 @@ public static class NaturalDisasters BuildingCollapse.CollapsedRooms.Clear(); BuildingCollapse.LastPosition.Clear(); - if (Options.CurrentGameMode != CustomGameMode.NaturalDisasters) return; + if (Options.CurrentGameMode != CustomGameMode.NaturalDisasters && !Options.IntegrateNaturalDisasters.GetBool()) return; Dictionary.ValueCollection rooms = RandomSpawn.SpawnMap.GetSpawnMap().Positions?.Values; if (rooms == null) return; @@ -201,7 +201,7 @@ public static class NaturalDisasters public static void Postfix( /*PlayerControl __instance*/) { - if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.NaturalDisasters || !Main.IntroDestroyed || Main.HasJustStarted || GameStartTimeStamp + 15 > Utils.TimeStamp /* || __instance.PlayerId >= 254 || !__instance.IsHost()*/) return; + if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks || (Options.CurrentGameMode != CustomGameMode.NaturalDisasters && !Options.IntegrateNaturalDisasters.GetBool()) || !Main.IntroDestroyed || Main.HasJustStarted || GameStartTimeStamp + 15 > Utils.TimeStamp /* || __instance.PlayerId >= 254 || !__instance.IsHost()*/) return; UpdatePreparingDisasters(); @@ -273,8 +273,15 @@ public static class NaturalDisasters PreparingDisasters.Add(new(position, warningTime, Sprite(disaster.Name), disaster.Name, room)); } - if (now - LastSync >= 10) + if (now - LastSync >= 15) { + if (Options.CurrentGameMode != CustomGameMode.NaturalDisasters) + { + BuildingCollapse.CollapsedRooms.Clear(); + Sinkhole.RemoveRandomSinkhole(); + Utils.NotifyRoles(); + } + LastSync = now; Utils.MarkEveryoneDirtySettings(); } diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index 9845612c5..762d8a13d 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -1303,6 +1303,15 @@ internal static class CustomRolesHelper return role.GetCount() > 0; } + public static bool IsDevFavoriteRole(this CustomRoles role) + { + return role is CustomRoles.Adventurer or CustomRoles.Chef or CustomRoles.Detour or CustomRoles.NiceHacker or CustomRoles.NiceSwapper or CustomRoles.Sentinel or CustomRoles.Sentry or CustomRoles.Tornado or CustomRoles.Tunneler or CustomRoles.Whisperer or CustomRoles.Wizard or + CustomRoles.Abyssbringer or CustomRoles.Assumer or CustomRoles.Chronomancer or CustomRoles.Echo or CustomRoles.Escapee or CustomRoles.Hypnotist or CustomRoles.Librarian or CustomRoles.Mafioso or CustomRoles.Mastermind or CustomRoles.SerialKiller or CustomRoles.Penguin or CustomRoles.RiftMaker or CustomRoles.Sapper or CustomRoles.Wiper or + CustomRoles.Bargainer or CustomRoles.Bubble or CustomRoles.Doomsayer or CustomRoles.Enderman or CustomRoles.Evolver or CustomRoles.HeadHunter or CustomRoles.Impartial or CustomRoles.Patroller or CustomRoles.Pawn or CustomRoles.PlagueDoctor or CustomRoles.Postman or CustomRoles.Pyromaniac or CustomRoles.Revolutionist or CustomRoles.Rogue or CustomRoles.Romantic or CustomRoles.RoomRusher or CustomRoles.RouleteGrandeur or CustomRoles.Simon or CustomRoles.SoulHunter or CustomRoles.Sprayer or CustomRoles.Technician or CustomRoles.Tank or CustomRoles.Tiger or CustomRoles.Tremor or CustomRoles.Vengeance or CustomRoles.Vortex or CustomRoles.Werewolf or CustomRoles.WeaponMaster or + CustomRoles.Reaper or CustomRoles.VoodooMaster or CustomRoles.Dreamweaver or CustomRoles.Banshee or + CustomRoles.Allergic or CustomRoles.Bloodlust or CustomRoles.Damocles or CustomRoles.Deadlined or CustomRoles.DeadlyQuota or CustomRoles.Dynamo or CustomRoles.DoubleShot or CustomRoles.Energetic or CustomRoles.Haste or CustomRoles.Introvert or CustomRoles.Messenger or CustomRoles.Nimble or CustomRoles.Reach or CustomRoles.Seer or CustomRoles.Stressed; + } + public static CountTypes GetCountTypes(this CustomRoles role) { return role switch diff --git a/Modules/FixedUpdateCaller.cs b/Modules/FixedUpdateCaller.cs index 2bf799923..90b59c9cc 100644 --- a/Modules/FixedUpdateCaller.cs +++ b/Modules/FixedUpdateCaller.cs @@ -80,21 +80,24 @@ public static class FixedUpdateCaller { case CustomGameMode.HideAndSeek: CustomHnS.FixedUpdatePatch.Postfix(); - break; + goto default; case CustomGameMode.FFA: FreeForAll.FixedUpdatePatch.Postfix(); - break; + goto default; case CustomGameMode.KingOfTheZones: KingOfTheZones.FixedUpdatePatch.Postfix(); - break; + goto default; case CustomGameMode.NaturalDisasters: NaturalDisasters.FixedUpdatePatch.Postfix(); break; case CustomGameMode.Quiz: Quiz.FixedUpdatePatch.Postfix(); - break; + goto default; case CustomGameMode.RoomRush: RoomRush.FixedUpdatePatch.Postfix(); + goto default; + default: + if (Options.IntegrateNaturalDisasters.GetBool()) goto case CustomGameMode.NaturalDisasters; break; } } diff --git a/Modules/GameState.cs b/Modules/GameState.cs index 8981b8026..221fe4d80 100644 --- a/Modules/GameState.cs +++ b/Modules/GameState.cs @@ -372,7 +372,7 @@ public class PlayerState(byte playerId) if (AmongUsClient.Instance.AmHost) { if (Enchanter.EnchantedPlayers.Contains(PlayerId)) - deathReason = Enum.GetValues().SkipLast(8).RandomElement(); + deathReason = Enum.GetValues()[..^8].RandomElement(); RPC.SendDeathReason(PlayerId, deathReason); Utils.CheckAndSpawnAdditionalRefugee(Utils.GetPlayerInfoById(PlayerId)); diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index d1c5fb56b..552fa3619 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -716,6 +716,7 @@ public static class Options public static OptionItem LargerRoleTextSize; public static OptionItem ShowTaskCountWhenAlive; public static OptionItem ShowTaskCountWhenDead; + public static OptionItem IntegrateNaturalDisasters; public static OptionItem ShowDifferentEjectionMessageForSomeRoles; public static OptionItem ShowAntiBlackoutWarning; public static OptionItem AllowConsole; @@ -2790,6 +2791,11 @@ public static class Options .SetGameMode(CustomGameMode.Standard) .SetColor(new Color32(193, 255, 209, byte.MaxValue)); + IntegrateNaturalDisasters = new BooleanOptionItem(24454, "IntegrateNaturalDisasters", false, TabGroup.GameSettings) + .SetGameMode(CustomGameMode.Standard) + .SetColor(new Color32(193, 255, 209, byte.MaxValue)) + .RegisterUpdateValueEvent((_, _) => GameOptionsMenuPatch.ReloadUI()); + new TextOptionItem(100029, "MenuTitle.Ghost", TabGroup.GameSettings) .SetGameMode(CustomGameMode.Standard) diff --git a/Modules/OptionItem/OptionItem.cs b/Modules/OptionItem/OptionItem.cs index 7551e0bb9..22aa3a067 100644 --- a/Modules/OptionItem/OptionItem.cs +++ b/Modules/OptionItem/OptionItem.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using EHR.Modules; using UnityEngine; @@ -223,20 +222,21 @@ public abstract class OptionItem public bool IsCurrentlyHidden() { - int lastParent = Id; - - for (var i = 0; i < 5; i++) + for (OptionItem current = this; current != null; current = current.Parent) { - if (AllOptions.First(x => x.Id == lastParent).Parent == null) break; - lastParent = AllOptions.First(x => x.Id == lastParent).Parent.Id; + if (Hidden(current)) + return true; } - return Hidden(this) || (Parent != null && Hidden(Parent)) || Hidden(AllOptions.First(x => x.Id == lastParent)); + return false; static bool Hidden(OptionItem oi) { CustomGameMode mode = EHR.Options.CurrentGameMode; - return oi.IsHidden || (oi.GameMode != CustomGameMode.All && oi.GameMode != mode); + const CustomGameMode nd = CustomGameMode.NaturalDisasters; + return (oi.IsHidden || (oi.GameMode != CustomGameMode.All && oi.GameMode != mode) || + (oi.Name == "IntegrateNaturalDisasters" && mode == nd)) && + !(oi.GameMode == nd && EHR.Options.IntegrateNaturalDisasters.GetBool()); } } diff --git a/Modules/OptionShower.cs b/Modules/OptionShower.cs index 584effbee..230b7cab6 100644 --- a/Modules/OptionShower.cs +++ b/Modules/OptionShower.cs @@ -2,7 +2,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using HarmonyLib; using UnityEngine; using static EHR.Translator; @@ -38,7 +37,7 @@ public static class OptionShower Pages = [ - GameOptionsManager.Instance.CurrentGameOptions.ToHudString(GameData.Instance ? GameData.Instance.PlayerCount : 10).Split('\n').SkipLast(8).Join(delimiter: "\n") + "\n\n" + string.Join('\n', GameOptionsManager.Instance.CurrentGameOptions.ToHudString(GameData.Instance ? GameData.Instance.PlayerCount : 10).Split('\n')[..^8]) + "\n\n" ]; sb.Append($"{Options.GameMode.GetName()}: {Options.GameMode.GetString()}\n\n"); diff --git a/Modules/TemplateManager.cs b/Modules/TemplateManager.cs index 98834503b..a2d55d219 100644 --- a/Modules/TemplateManager.cs +++ b/Modules/TemplateManager.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -106,13 +105,13 @@ public static class TemplateManager while (sr.ReadLine() is { } text) { - string[] tmp = text.Split(":"); + string[] tmp = text.Split(':'); if (tmp.Length > 1 && tmp[1] != "") { tags.Add(tmp[0]); if (string.Equals(tmp[0], str, StringComparison.CurrentCultureIgnoreCase)) - sendList.Add(tmp.Skip(1).Join(delimiter: ":").Replace("\\n", "\n")); + sendList.Add(string.Join(':', tmp[1..]).Replace("\\n", "\n")); } } diff --git a/Modules/Translator.cs b/Modules/Translator.cs index 2001f0684..55bf07b89 100644 --- a/Modules/Translator.cs +++ b/Modules/Translator.cs @@ -7,7 +7,6 @@ using System.Reflection; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; -using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; namespace EHR; @@ -254,11 +253,11 @@ public static class Translator while (sr.ReadLine() is { } text) { - string[] tmp = text.Split(":"); + string[] tmp = text.Split(':'); if (tmp.Length > 1 && tmp[1] != "") { - try { TranslateMaps[tmp[0]][(int)lang] = tmp.Skip(1).Join(delimiter: ":").Replace("\\n", "\n").Replace("\\r", "\r"); } + try { TranslateMaps[tmp[0]][(int)lang] = string.Join(':', tmp[1..]).Replace("\\n", "\n").Replace("\\r", "\r"); } catch (KeyNotFoundException) { Logger.Warn($"Invalid Key: {tmp[0]}", "LoadCustomTranslation"); } } } diff --git a/Patches/AnnouncementPatch.cs b/Patches/AnnouncementPatch.cs index b6b6f5428..3900ef56c 100644 --- a/Patches/AnnouncementPatch.cs +++ b/Patches/AnnouncementPatch.cs @@ -99,5 +99,4 @@ public static class ModNewsHistory for (var i = 0; i < finalAllNews.Count; i++) aRange[i] = finalAllNews[i]; } - } \ No newline at end of file diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index a489a1ee1..384943663 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -191,6 +191,7 @@ internal static class ChatCommands new(["achievements", "достижения", "成就", "conquistas"], "", GetString("CommandDescription.Achievements"), Command.UsageLevels.Modded, Command.UsageTimes.Always, AchievementsCommand, true, false), new(["dn", "deathnote", "заметкамертвого", "死亡笔记"], "{name}", GetString("CommandDescription.DeathNote"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, DeathNoteCommand, true, true, [GetString("CommandArgs.DeathNote.Name")]), new(["w", "whisper", "шепот", "ш", "私聊", "sussurrar"], "{id} {message}", GetString("CommandDescription.Whisper"), Command.UsageLevels.Everyone, Command.UsageTimes.InMeeting, WhisperCommand, true, true, [GetString("CommandArgs.Whisper.Id"), GetString("CommandArgs.Whisper.Message")]), + new(["hw", "hwhisper"], "{id} {message}", GetString("CommandDescription.HWhisper"), Command.UsageLevels.Host, Command.UsageTimes.Always, HWhisperCommand, true, true, [GetString("CommandArgs.HWhisper.Id"), GetString("CommandArgs.HWhisper.Message")]), new(["spectate", "спектейт", "观战", "espectar"], "[id]", GetString("CommandDescription.Spectate"), Command.UsageLevels.Everyone, Command.UsageTimes.InLobby, SpectateCommand, false, false, [GetString("CommandArgs.Spectate.Id")]), new(["anagram", "анаграмма"], "", GetString("CommandDescription.Anagram"), Command.UsageLevels.Everyone, Command.UsageTimes.Always, AnagramCommand, true, false), new(["rl", "rolelist", "роли"], "", GetString("CommandDescription.RoleList"), Command.UsageLevels.Everyone, Command.UsageTimes.Always, RoleListCommand, true, false), @@ -585,7 +586,7 @@ internal static class ChatCommands return; } - string gmNames = string.Join(' ', Enum.GetNames().SkipLast(1).Select(x => GetString(x).Replace(' ', '_'))); + string gmNames = string.Join(' ', Enum.GetNames()[..^1].Select(x => GetString(x).Replace(' ', '_'))); var msg = $"/poll {GetString("GameModePoll.Question").TrimEnd('?')}? {gmNames}"; PollCommand(player, msg, msg.Split(' ')); } @@ -598,7 +599,7 @@ internal static class ChatCommands return; } - string info = string.Join("\n\n", Enum.GetValues()[1..].SkipLast(1) + string info = string.Join("\n\n", Enum.GetValues()[1..^1] .Select(x => (GameMode: x, Color: Main.RoleColors.GetValueOrDefault(CustomRoleSelector.GameModeRoles.TryGetValue(x, out CustomRoles role) ? role : x == CustomGameMode.HideAndSeek ? CustomRoles.Hider : CustomRoles.Witness, "#000000"))) .Select(x => $"<{x.Color}>{GetString($"{x.GameMode}")}\n{GetString($"ModeDescribe.{x.GameMode}").Split("\n\n")[0]}")); @@ -821,6 +822,17 @@ internal static class ChatCommands ChatUpdatePatch.LastMessages.Add((msg, targetId, title, Utils.TimeStamp)); } + private static void HWhisperCommand(PlayerControl player, string text, string[] args) + { + if (args.Length < 3 || !byte.TryParse(args[1], out byte targetId)) return; + + string msg = args[2..].Join(delimiter: " "); + string title = string.Format(GetString("HWhisperTitle"), player.PlayerId.ColoredPlayerName()); + + Utils.SendMessage(msg, targetId, title); + ChatUpdatePatch.LastMessages.Add((msg, targetId, title, Utils.TimeStamp)); + } + private static void DeathNoteCommand(PlayerControl player, string text, string[] args) { if (Starspawn.IsDayBreak) return; @@ -2442,7 +2454,7 @@ internal static class ChatCommands return; } - Main.HideName.Value = args.Length > 1 ? args.Skip(1).Join(delimiter: " ") : Main.HideName.DefaultValue.ToString(); + Main.HideName.Value = args.Length > 1 ? string.Join(' ', args[1..]) : Main.HideName.DefaultValue.ToString(); GameStartManagerPatch.GameStartManagerStartPatch.HideName.text = ColorUtility.TryParseHtmlString(Main.HideColor.Value, out _) @@ -2480,7 +2492,7 @@ internal static class ChatCommands return; } - string name = args.Skip(1).Join(delimiter: " "); + string name = string.Join(' ', args[1..]); if (name.Length is > 50 or < 1) { diff --git a/Patches/GameOptionsMenuPatch.cs b/Patches/GameOptionsMenuPatch.cs index 421a82dd2..393f89e35 100644 --- a/Patches/GameOptionsMenuPatch.cs +++ b/Patches/GameOptionsMenuPatch.cs @@ -680,6 +680,7 @@ public static class StringOptionPatch if (role.IsExperimental()) name += $"{Translator.GetString("ExperimentalRoleIndicator")}"; if (role.IsGhostRole()) name += GetGhostRoleTeam(role); + if (role.IsDevFavoriteRole()) name += "<#00ffff>★"; __instance.TitleText.fontWeight = FontWeight.Black; __instance.TitleText.outlineColor = new(255, 255, 255, 255); @@ -821,6 +822,7 @@ public static class StringOptionPatch if (role.IsExperimental()) name += $"{Translator.GetString("ExperimentalRoleIndicator")}"; if (role.IsGhostRole()) name += GetGhostRoleTeam(role); + if (role.IsDevFavoriteRole()) name += "<#00ffff>★"; __instance.TitleText.fontWeight = FontWeight.Black; __instance.TitleText.outlineColor = new(255, 255, 255, 255); @@ -1115,7 +1117,7 @@ public static class GameSettingMenuPatch Vector3 gameSettingsLabelPos = gameSettingsLabel.transform.localPosition; - CustomGameMode[] gms = Enum.GetValues().SkipLast(1).ToArray(); + CustomGameMode[] gms = Enum.GetValues()[..^1]; int totalCols = Mathf.Max(1, Mathf.CeilToInt(gms.Length / 5f)); GMButtons = []; diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index 1acac1de1..26fa7d3f9 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -2437,6 +2437,7 @@ "CommandDescription.Achievements": "See which achievements you have unlocked and which you haven't", "CommandDescription.DeathNote": "Guess someone's real name as the Note Killer.", "CommandDescription.Whisper": "Whisper a message to a player.", + "CommandDescription.HWhisper": "Whisper a helping message to a player as the Host.", "CommandDescription.Spectate": "Makes you a spectator for the next game. You should just enable Game Master as the host.", "CommandDescription.Anagram": "Get a random scrambled word, then try to guess the original word.", "CommandDescription.RoleList": "View the limits of how many of each faction and subcategory of roles will spawn.", @@ -2523,6 +2524,8 @@ "CommandArgs.DeathNote.Name": "The real name to guess. If it's correct, you kill the player with this name.", "CommandArgs.Whisper.Id": "The player's ID to whisper to", "CommandArgs.Whisper.Message": "The message to whisper", + "CommandArgs.HWhisper.Id": "The player's ID to whisper the help to", + "CommandArgs.HWhisper.Message": "The helping message to whisper", "CommandArgs.Spectate.Id": "The player's ID who will be forced to spectate (leave blank to use it on yourself)", "CommandArgs.JailTalk.Message": "The message to send to the Jailor/jailed player", "CommandArgs.EightBall.Question": "The question to ask", @@ -2581,6 +2584,7 @@ "YouUnmuted": "{0} has unmuted you.", "MuteMessage": "<#ff0000>You're muted and cannot send messages. The mute will expire in <#ffff00>{0} seconds.", "WhisperTitle": "{0} <#ffffff>(ID <#00ffa5>{1}) whispers to you:", + "HWhisperTitle": "<#ff0000>The Host ({0}) whispers a <#00ffff>help to you:", "JailTalkTitle": "JAIL", "DisableWhisperCommand": "Disable /whisper command", "DisableSpectateCommand": "Disable /spectate command", @@ -3250,6 +3254,7 @@ "LargerRoleTextSize": "Larger Role Text Size", "ShowTaskCountWhenAlive": "Show Task Count When Alive", "ShowTaskCountWhenDead": "Show Task Count When Dead", + "IntegrateNaturalDisasters": "Integrate the Natural Disasters game mode into the current game mode", "GameOverReason.CrewmatesByVote": "All Evil Players were ejected or killed", "GameOverReason.CrewmateDisconnect": "Crewmates disconnected", "GameOverReason.ImpostorsByKill": "The Impostors killed everyone", diff --git a/Roles/Neutral/Dealer.cs b/Roles/Neutral/Dealer.cs index 9cdaa0264..0aa2c3c1b 100644 --- a/Roles/Neutral/Dealer.cs +++ b/Roles/Neutral/Dealer.cs @@ -49,6 +49,11 @@ public class Dealer : RoleBase AssignedNum = 0; } + public override bool CanUseKillButton(PlayerControl pc) + { + return pc.IsAlive(); + } + public override void SetKillCooldown(byte id) { Main.AllPlayerKillCooldown[id] = AbilityCooldown.GetFloat();