From 2f456b5d0ac4f0032bf5b56c97914804c8a50da8 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Wed, 28 Feb 2024 22:17:38 +0100 Subject: [PATCH] Fix a lot of errors (still some to go) --- GameMode/FFAManager.cs | 6 +- GameMode/HotPotatoManager.cs | 4 +- GameMode/MoveAndStopManager.cs | 161 ++- GameMode/SoloKombatManager.cs | 39 +- Modules/AntiBlackout.cs | 54 +- Modules/BanManager.cs | 409 ++++--- Modules/Camouflague.cs | 25 +- Modules/ClientOptionItem.cs | 4 +- Modules/Cloud.cs | 15 +- Modules/CustomRoleSelector.cs | 63 +- Modules/CustomRolesHelper.cs | 8 +- Modules/CustomRpcSender.cs | 4 +- Modules/CustomSounds.cs | 17 +- Modules/CustomWinnerHolder.cs | 10 +- Modules/DisableDevice.cs | 18 +- Modules/EAC.cs | 8 +- Modules/ExtendedPlayerControl.cs | 708 ++--------- .../GameOptionsSender/GameOptionsSender.cs | 9 +- .../NormalGameOptionsSender.cs | 10 +- .../PlayerGameOptionsSender.cs | 22 +- Modules/GameState.cs | 62 +- Modules/GuessManager.cs | 6 +- Modules/LoadingScreen.cs | 7 +- Modules/MafiaRevengeManager.cs | 13 +- Modules/MeetingTimeManager.cs | 7 +- Modules/ModUpdater.cs | 27 +- Modules/NameColorManager.cs | 9 + Modules/NameNotifyManager.cs | 10 +- Modules/OptionBackup/OptionBackupData.cs | 2 +- Modules/OptionBackup/OptionBackupValue.cs | 8 +- Modules/OptionHolder.cs | 2 +- Modules/RPC.cs | 2 - Modules/ServerAddManager.cs | 11 +- Modules/TemplateManager.cs | 6 +- Modules/Translator.cs | 4 +- Modules/Utils.cs | 1029 ++-------------- Modules/Zoom.cs | 17 +- Patches/AirShipElectricalDoors.cs | 8 +- Patches/AnnouncementPatch.cs | 48 +- Patches/ChatCommandPatch.cs | 7 +- Patches/ChatControlPatch.cs | 17 +- Patches/ControlPatch.cs | 37 +- Patches/CredentialsPatch.cs | 8 +- Patches/DiscordPatch.cs | 5 +- Patches/ExilePatch.cs | 2 +- Patches/GameOptionsMenuPatch.cs | 6 +- Patches/GameStartManagerPatch.cs | 52 +- Patches/HudPatch.cs | 139 +-- Patches/HudSpritePatch.cs | 1 + Patches/IntroPatch.cs | 6 +- Patches/JoinGameButtonPatch.cs | 2 +- Patches/LadderPatch.cs | 18 +- Patches/LobbyListPatch.cs | 30 +- Patches/LogoAndStampPatch.cs | 10 +- Patches/MainMenuManagerPatch.cs | 12 +- Patches/MeetingHudPatch.cs | 2 +- Patches/OutroPatch.cs | 2 +- Patches/PetActionsPatch.cs | 301 +---- Patches/PlayerContorolPatch.cs | 1071 ++--------------- Patches/PlayerJoinAndLeftPatch.cs | 35 +- Patches/RandomSpawnPatch.cs | 17 +- Patches/SabotageSystemPatch.cs | 2 +- Patches/ShipStatusPatch.cs | 100 +- Patches/TaskAdderPatch.cs | 17 +- Patches/onGameStartedPatch.cs | 123 +- Roles/AddOns/Crewmate/Stressed.cs | 7 +- Roles/AddOns/Impostor/Damocles.cs | 13 +- Roles/Crewmate/Aid.cs | 1 + Roles/Crewmate/Alchemist.cs | 6 + Roles/Crewmate/Analyzer.cs | 4 +- Roles/Crewmate/Bloodhound.cs | 8 +- Roles/Crewmate/CandleLighter.cs | 4 +- Roles/Crewmate/Cleanser.cs | 4 +- Roles/Crewmate/CopyCat.cs | 21 +- Roles/Crewmate/Crusader.cs | 1 + Roles/Crewmate/Deputy.cs | 1 + Roles/Crewmate/Doctor.cs | 9 +- Roles/Crewmate/DonutDelivery.cs | 2 + Roles/Crewmate/Drainer.cs | 6 +- Roles/Crewmate/Druid.cs | 11 +- Roles/Crewmate/Escort.cs | 2 + Roles/Crewmate/Farseer.cs | 13 +- Roles/Crewmate/Gaulois.cs | 2 + Roles/Crewmate/Grenadier.cs | 10 +- Roles/Crewmate/Jailer.cs | 3 +- Roles/Crewmate/Judge.cs | 6 +- Roles/Crewmate/Lookout.cs | 8 +- Roles/Crewmate/Luckey.cs | 10 +- Roles/Crewmate/Mayor.cs | 9 +- Roles/Crewmate/Medic.cs | 11 +- Roles/Crewmate/Monarch.cs | 1 + Roles/Crewmate/Mortician.cs | 8 +- Roles/Crewmate/NiceHacker.cs | 4 +- Roles/Crewmate/Paranoia.cs | 9 +- Roles/Crewmate/ParityCop.cs | 2 +- Roles/Crewmate/Psychic.cs | 18 +- Roles/Crewmate/Rabbit.cs | 13 +- Roles/Crewmate/Randomizer.cs | 5 +- Roles/Crewmate/SabotageMaster.cs | 2 +- Roles/Crewmate/Sentinel.cs | 3 +- Roles/Crewmate/Sheriff.cs | 2 + Roles/Crewmate/Spy.cs | 6 +- Roles/Crewmate/SwordsMan.cs | 6 +- Roles/Crewmate/Tether.cs | 10 +- Roles/Crewmate/Tornado.cs | 9 +- Roles/Crewmate/Tracefinder.cs | 8 +- Roles/Crewmate/Tracker.cs | 11 +- Roles/Crewmate/VanillaRole.cs | 10 +- Roles/Impostor/Assassin.cs | 5 +- Roles/Impostor/BallLightning.cs | 4 +- Roles/Impostor/Blackmailer.cs | 6 + Roles/Impostor/BountyHunter.cs | 2 +- Roles/Impostor/Chronomancer.cs | 9 +- Roles/Impostor/Councillor.cs | 6 +- Roles/Impostor/Crewpostor.cs | 12 +- Roles/Impostor/Dazzler.cs | 3 +- Roles/Impostor/Devourer.cs | 4 +- Roles/Impostor/Duellist.cs | 6 +- Roles/Impostor/Escapee.cs | 1 - Roles/Impostor/EvilDiviner.cs | 41 +- Roles/Impostor/EvilTracker.cs | 8 +- Roles/Impostor/FireWorks.cs | 2 +- Roles/Impostor/Gambler.cs | 5 + Roles/Impostor/Gangster.cs | 3 - Roles/Impostor/Godfather.cs | 10 +- Roles/Impostor/Greedier.cs | 6 +- Roles/Impostor/Hacker.cs | 2 - Roles/Impostor/Hangman.cs | 5 +- Roles/Impostor/Hitman.cs | 18 +- Roles/Impostor/Librarian.cs | 5 +- Roles/Impostor/Mafioso.cs | 6 +- Roles/Impostor/Mastermind.cs | 5 + Roles/Impostor/QuickShooter.cs | 4 +- Roles/Impostor/RiftMaker.cs | 7 +- Roles/Impostor/Sans.cs | 4 +- Roles/Impostor/Sapper.cs | 19 +- Roles/Impostor/Sniper.cs | 2 +- Roles/Impostor/Stealth.cs | 4 +- Roles/Impostor/Swooper.cs | 6 +- Roles/Impostor/Underdog.cs | 11 +- Roles/Impostor/Undertaker.cs | 9 +- Roles/Impostor/Vampire.cs | 7 +- Roles/Impostor/Wildling.cs | 4 +- Roles/Neutral/Agitater.cs | 10 +- Roles/Neutral/Amnesiac.cs | 11 +- Roles/Neutral/Arsonist.cs | 109 +- Roles/Neutral/Bandit.cs | 10 +- Roles/Neutral/Bubble.cs | 11 +- Roles/Neutral/Collector.cs | 17 +- Roles/Neutral/DarkHide.cs | 9 +- Roles/Neutral/Doomsayer.cs | 7 +- Roles/Neutral/Doppelganger.cs | 16 +- Roles/Neutral/Eclipse.cs | 5 +- Roles/Neutral/Enderman.cs | 2 + Roles/Neutral/Executioner.cs | 4 +- Roles/Neutral/FFF.cs | 1 + Roles/Neutral/Gamer.cs | 16 +- Roles/Neutral/Glitch.cs | 71 +- Roles/Neutral/HeadHunter.cs | 14 +- Roles/Neutral/Hookshot.cs | 2 + Roles/Neutral/Jackal.cs | 2 + Roles/Neutral/Jester.cs | 9 +- Roles/Neutral/Jinx.cs | 2 - Roles/Neutral/Lawyer.cs | 4 +- Roles/Neutral/Magician.cs | 25 +- Roles/Neutral/Maverick.cs | 11 +- Roles/Neutral/Mycologist.cs | 8 +- Roles/Neutral/NSerialKiller.cs | 4 +- Roles/Neutral/Necromancer.cs | 4 + Roles/Neutral/Opportunist.cs | 10 +- Roles/Neutral/Pelican.cs | 28 +- Roles/Neutral/Pickpocket.cs | 7 +- Roles/Neutral/PlagueBearer.cs | 2 + Roles/Neutral/PlagueDoctor.cs | 7 +- Roles/Neutral/Postman.cs | 8 +- Roles/Neutral/Provocateur.cs | 9 +- Roles/Neutral/Pyromaniac.cs | 5 +- Roles/Neutral/Ritualist.cs | 112 +- Roles/Neutral/Romantic.cs | 24 +- Roles/Neutral/Sidekick.cs | 6 +- Roles/Neutral/SoulHunter.cs | 10 +- Roles/Neutral/Spiritcaller.cs | 1 + Roles/Neutral/Sprayer.cs | 6 +- Roles/Neutral/Succubus.cs | 1 + Roles/Neutral/Sunnyboy.cs | 9 +- Roles/Neutral/Totocalcio.cs | 8 +- Roles/Neutral/Traitor.cs | 5 +- Roles/Neutral/Vengeance.cs | 12 +- Roles/Neutral/Virus.cs | 1 + Roles/Neutral/Vulture.cs | 16 +- Roles/Neutral/WeaponMaster.cs | 14 +- Roles/Neutral/Werewolf.cs | 2 + Roles/RoleBase.cs | 17 + main.cs | 8 +- 194 files changed, 2048 insertions(+), 4108 deletions(-) diff --git a/GameMode/FFAManager.cs b/GameMode/FFAManager.cs index 008a309d4..ec43d84bd 100644 --- a/GameMode/FFAManager.cs +++ b/GameMode/FFAManager.cs @@ -1,8 +1,8 @@ -using System; +using HarmonyLib; +using Hazel; +using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; -using Hazel; using TOHE.Modules; using UnityEngine; using static TOHE.Translator; diff --git a/GameMode/HotPotatoManager.cs b/GameMode/HotPotatoManager.cs index 63e8cd674..b43c5ea2f 100644 --- a/GameMode/HotPotatoManager.cs +++ b/GameMode/HotPotatoManager.cs @@ -1,7 +1,7 @@ -using System; +using HarmonyLib; +using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; using UnityEngine; namespace TOHE diff --git a/GameMode/MoveAndStopManager.cs b/GameMode/MoveAndStopManager.cs index 93c214acd..bd5fbd950 100644 --- a/GameMode/MoveAndStopManager.cs +++ b/GameMode/MoveAndStopManager.cs @@ -1,7 +1,7 @@ -using System; +using HarmonyLib; +using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; using TOHE.Roles.AddOns.Common; using UnityEngine; using static TOHE.Translator; @@ -10,20 +10,65 @@ namespace TOHE; public class Counter(int totalGreenTime, int totalRedTime, long startTimeStamp, char symbol, bool isRed, bool isYellow = false, bool moveAndStop = true) { - public int TotalGreenTime { get => totalGreenTime; set => totalGreenTime = value; } - public int TotalRedTime { get => totalRedTime; set => totalRedTime = value; } - public long StartTimeStamp { get => startTimeStamp; set => startTimeStamp = value; } - public char Symbol { get => symbol; set => symbol = value; } - public bool IsRed { get => isRed; set => isRed = value; } - public bool IsYellow { get => isYellow; set => isYellow = value; } - public bool MoveAndStop { get => moveAndStop; set => moveAndStop = value; } + public int TotalGreenTime + { + get => totalGreenTime; + set => totalGreenTime = value; + } + + public int TotalRedTime + { + get => totalRedTime; + set => totalRedTime = value; + } + + public long StartTimeStamp + { + get => startTimeStamp; + set => startTimeStamp = value; + } + + public char Symbol + { + get => symbol; + set => symbol = value; + } + + public bool IsRed + { + get => isRed; + set => isRed = value; + } + + public bool IsYellow + { + get => isYellow; + set => isYellow = value; + } + + public bool MoveAndStop + { + get => moveAndStop; + set => moveAndStop = value; + } private static int TotalYellowTime => 3; private static Color32 Orange => new(255, 165, 0, 255); - public int Timer { get => (IsRed ? TotalRedTime : IsYellow ? TotalYellowTime : TotalGreenTime) - (int)Math.Round((double)(Utils.TimeStamp - StartTimeStamp)); } - public string ColoredTimerString { get => IsYellow ? Utils.ColorString(Color.black, "00") : Utils.ColorString(IsRed ? Color.red : Color.green, Timer < 10 ? $"0{Timer}" : Timer.ToString()); } - public string ColoredArrow { get => Utils.ColorString(IsRed ? Timer <= 2 ? Orange : Color.red : IsYellow ? Color.yellow : Color.green, Symbol.ToString()); } + public int Timer + { + get => (IsRed ? TotalRedTime : IsYellow ? TotalYellowTime : TotalGreenTime) - (int)Math.Round((double)(Utils.TimeStamp - StartTimeStamp)); + } + + public string ColoredTimerString + { + get => IsYellow ? Utils.ColorString(Color.black, "00") : Utils.ColorString(IsRed ? Color.red : Color.green, Timer < 10 ? $"0{Timer}" : Timer.ToString()); + } + + public string ColoredArrow + { + get => Utils.ColorString(IsRed ? Timer <= 2 ? Orange : Color.red : IsYellow ? Color.yellow : Color.green, Symbol.ToString()); + } public void Update() { @@ -44,17 +89,43 @@ public class Counter(int totalGreenTime, int totalRedTime, long startTimeStamp, IsYellow = false; IsRed = true; } + StartTimeStamp = Utils.TimeStamp; } } } + class MoveAndStopPlayerData(Counter leftCounter, Counter middleCounter, Counter rightCounter, float position_x, float position_y) { - public Counter LeftCounter { get => leftCounter; set => leftCounter = value; } - public Counter MiddleCounter { get => middleCounter; set => middleCounter = value; } - public Counter RightCounter { get => rightCounter; set => rightCounter = value; } - public float Position_X { get => position_x; set => position_x = value; } - public float Position_Y { get => position_y; set => position_y = value; } + public Counter LeftCounter + { + get => leftCounter; + set => leftCounter = value; + } + + public Counter MiddleCounter + { + get => middleCounter; + set => middleCounter = value; + } + + public Counter RightCounter + { + get => rightCounter; + set => rightCounter = value; + } + + public float Position_X + { + get => position_x; + set => position_x = value; + } + + public float Position_Y + { + get => position_y; + set => position_y = value; + } public override string ToString() { @@ -75,21 +146,29 @@ class MoveAndStopPlayerData(Counter leftCounter, Counter middleCounter, Counter RightCounter.Update(); } } + internal class MoveAndStopManager { private static Dictionary AllPlayerTimers = []; private static IRandom Random => IRandom.Instance; private static int roundTime; - public static int RoundTime { get => roundTime; set => roundTime = value; } + + public static int RoundTime + { + get => roundTime; + set => roundTime = value; + } private static int StartingGreenTime => (MapNames)Main.NormalOptions.MapId == MapNames.Airship ? 25 : 20; + private static int ExtraGreenTime => (MapNames)Main.NormalOptions.MapId switch { MapNames.Airship => MoveAndStop_ExtraGreenTimeOnAirhip.GetInt(), MapNames.Fungle => MoveAndStop_ExtraGreenTimeOnFungle.GetInt(), _ => 0 }; + public static int RandomRedTime(char direction) => direction switch { '→' => Random.Next(MoveAndStop_RightCounterRedMin.GetInt(), MoveAndStop_RightCounterRedMax.GetInt()), @@ -97,6 +176,7 @@ internal class MoveAndStopManager '←' => Random.Next(MoveAndStop_LeftCounterRedMin.GetInt(), MoveAndStop_LeftCounterRedMax.GetInt()), _ => throw new NotImplementedException(), }; + public static int RandomGreenTime(char direction) => ExtraGreenTime + direction switch { '→' => Random.Next(MoveAndStop_RightCounterGreenMin.GetInt(), MoveAndStop_RightCounterGreenMax.GetInt()), @@ -126,24 +206,26 @@ internal class MoveAndStopManager private static IntegerValueRule ExtraTimeValue => new(0, 50, 1); private static int DefaultMinValue => 5; private static int DefaultMaxValue => 30; + private static OptionItem CreateSetting(int Id, string direction, bool red, bool min) => - IntegerOptionItem.Create(Id, CounterSettingString(direction, red, min), CounterValueRule, min ? DefaultMinValue : DefaultMaxValue, TabGroup.GameSettings, false) - .SetGameMode(CustomGameMode.MoveAndStop) - .SetColor(new Color32(0, 255, 255, byte.MaxValue)) - .SetValueFormat(OptionFormat.Seconds) - .AddReplacement(new("Red", Utils.ColorString(Color.red, "Red"))) - .AddReplacement(new("Green", Utils.ColorString(Color.green, "Green"))) - .AddReplacement(new("Minimum", Utils.ColorString(Color.blue, "Minimum"))) - .AddReplacement(new("Maximum", Utils.ColorString(Color.gray, "Maximum"))) - .AddReplacement(new("Right", Utils.ColorString(Color.magenta, "Right"))) - .AddReplacement(new("Left", Utils.ColorString(Color.yellow, "Left"))) - .AddReplacement(new("Middle", Utils.ColorString(Color.white, "Middle"))); + IntegerOptionItem.Create(Id, CounterSettingString(direction, red, min), CounterValueRule, min ? DefaultMinValue : DefaultMaxValue, TabGroup.GameSettings, false) + .SetGameMode(CustomGameMode.MoveAndStop) + .SetColor(new Color32(0, 255, 255, byte.MaxValue)) + .SetValueFormat(OptionFormat.Seconds) + .AddReplacement(new("Red", Utils.ColorString(Color.red, "Red"))) + .AddReplacement(new("Green", Utils.ColorString(Color.green, "Green"))) + .AddReplacement(new("Minimum", Utils.ColorString(Color.blue, "Minimum"))) + .AddReplacement(new("Maximum", Utils.ColorString(Color.gray, "Maximum"))) + .AddReplacement(new("Right", Utils.ColorString(Color.magenta, "Right"))) + .AddReplacement(new("Left", Utils.ColorString(Color.yellow, "Left"))) + .AddReplacement(new("Middle", Utils.ColorString(Color.white, "Middle"))); + private static OptionItem CreateExtraTimeSetting(int Id, string mapName, int defaultValue) => - IntegerOptionItem.Create(Id, $"MoveAndStop_ExtraGreenTimeOn{mapName}", ExtraTimeValue, defaultValue, TabGroup.GameSettings, false) - .SetGameMode(CustomGameMode.MoveAndStop) - .SetColor(new Color32(0, 255, 255, byte.MaxValue)) - .SetValueFormat(OptionFormat.Seconds) - .AddReplacement(new("Green", Utils.ColorString(Color.green, "Green"))); + IntegerOptionItem.Create(Id, $"MoveAndStop_ExtraGreenTimeOn{mapName}", ExtraTimeValue, defaultValue, TabGroup.GameSettings, false) + .SetGameMode(CustomGameMode.MoveAndStop) + .SetColor(new Color32(0, 255, 255, byte.MaxValue)) + .SetValueFormat(OptionFormat.Seconds) + .AddReplacement(new("Green", Utils.ColorString(Color.green, "Green"))); public static void SetupCustomOption() { @@ -194,7 +276,7 @@ internal class MoveAndStopManager try { limit = pc.GetClient().PlatformData.Platform is Platforms.Unknown or Platforms.IPhone or Platforms.Android or Platforms.Switch or Platforms.Xbox or Platforms.Playstation - ? 2f // If the player has a joystick, the game is a lot harder + ? 2f // If the player has a joystick, the game is a lot harder : 0.5f; // On PC you have WASD, you can't mess up } catch @@ -205,6 +287,7 @@ internal class MoveAndStopManager FixedUpdatePatch.Limit[pc.PlayerId] = limit; } } + public static int GetRankOfScore(byte playerId) { try @@ -219,6 +302,7 @@ internal class MoveAndStopManager return Main.AllPlayerControls.Length; } } + public static string HUDText => string.Format(GetString("KBTimeRemain"), RoundTime.ToString()); public static string GetSuffixText(PlayerControl pc) => !pc.IsAlive() ? string.Empty : AllPlayerTimers.TryGetValue(pc.PlayerId, out var timers) ? timers.ToString() : string.Empty; @@ -229,6 +313,7 @@ internal class MoveAndStopManager private static long LastFixedUpdate; public static Dictionary LastSuffix = []; public static Dictionary Limit = []; + public static void Postfix(PlayerControl __instance) { if (!GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.MoveAndStop || !__instance.IsAlive() || !AmongUsClient.Instance.AmHost || !DoChecks) return; @@ -270,6 +355,7 @@ internal class MoveAndStopManager data.Position_X = currentPosition.x; // Update the player's last position regardless of the distance } } + if (direction.x < 0) // Player is moving left { if (data.LeftCounter.IsRed && distanceX < -limit) // The distance is negative here because it's the opposite direction as right @@ -283,6 +369,7 @@ internal class MoveAndStopManager data.Position_X = currentPosition.x; } } + if (direction.y is > 0 or < 0) // y > 0 means the player is moving up, y < 0 means the player is moving down { if (data.MiddleCounter.IsRed && (distanceY > limit || distanceY < -limit)) // The player dies if either they moved up OR down too far @@ -297,7 +384,7 @@ internal class MoveAndStopManager } } - End: + End: data.UpdateCounters(); @@ -313,7 +400,7 @@ internal class MoveAndStopManager LastSuffix[pc.PlayerId] = suffix; } - NoSuffix: + NoSuffix: long now = Utils.TimeStamp; if (LastFixedUpdate == now) return; diff --git a/GameMode/SoloKombatManager.cs b/GameMode/SoloKombatManager.cs index ea46d4373..a812378cd 100644 --- a/GameMode/SoloKombatManager.cs +++ b/GameMode/SoloKombatManager.cs @@ -1,8 +1,8 @@ -using System; +using HarmonyLib; +using Hazel; +using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; -using Hazel; using TOHE.Roles.Neutral; using UnityEngine; using static TOHE.RandomSpawn; @@ -109,6 +109,7 @@ internal static class SoloKombatManager LastHurt.TryAdd(pc.PlayerId, Utils.TimeStamp); } } + private static void SendRPCSyncKBBackCountdown(PlayerControl player) { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncKBBackCountdown, SendOption.Reliable, player.GetClientId()); @@ -116,6 +117,7 @@ internal static class SoloKombatManager writer.Write(x); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPCSyncBackCountdown(MessageReader reader) { int num = reader.ReadInt32(); @@ -127,6 +129,7 @@ internal static class SoloKombatManager BackCountdown[PlayerControl.LocalPlayer.PlayerId] = num; } } + private static void SendRPCSyncKBPlayer(byte playerId) { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncKBPlayer, SendOption.Reliable); @@ -139,6 +142,7 @@ internal static class SoloKombatManager writer.Write(KBScore[playerId]); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPCSyncKBPlayer(MessageReader reader) { byte PlayerId = reader.ReadByte(); @@ -149,6 +153,7 @@ internal static class SoloKombatManager PlayerDF[PlayerId] = reader.ReadSingle(); KBScore[PlayerId] = reader.ReadInt32(); } + public static void SendRPCSyncNameNotify(PlayerControl pc) { if (pc.AmOwner || !pc.IsModClient()) return; @@ -158,6 +163,7 @@ internal static class SoloKombatManager else writer.Write(""); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPCSyncNameNotify(MessageReader reader) { var name = reader.ReadString(); @@ -165,16 +171,23 @@ internal static class SoloKombatManager if (name != null && name != "") NameNotify.Add(PlayerControl.LocalPlayer.PlayerId, (name, 0)); } + public static string GetDisplayHealth(PlayerControl pc) => pc.SoloAlive() ? Utils.ColorString(GetHealthColor(pc), $"{(int)pc.HP()}/{(int)pc.HPMAX()}") : ""; + private static Color32 GetHealthColor(PlayerControl pc) { var x = (int)(pc.HP() / pc.HPMAX() * 10 * 50); - int R = 255; int G = 255; int B = 0; - if (x > 255) R -= x - 255; else G = x; + int R = 255; + int G = 255; + int B = 0; + if (x > 255) R -= x - 255; + else G = x; return new Color32((byte)R, (byte)G, (byte)B, byte.MaxValue); } + public static Dictionary NameNotify = []; + public static void GetNameNotify(PlayerControl player, ref string name) { if (Options.CurrentGameMode != CustomGameMode.SoloKombat || player == null) return; @@ -190,6 +203,7 @@ internal static class SoloKombatManager name = value1.TEXT; } } + public static string GetDisplayScore(byte playerId) { int rank = GetRankOfScore(playerId); @@ -198,6 +212,7 @@ internal static class SoloKombatManager Color color = Utils.GetRoleColor(CustomRoles.KB_Normal); return Utils.ColorString(color, text); } + public static int GetRankOfScore(byte playerId) { try @@ -212,10 +227,12 @@ internal static class SoloKombatManager return Main.AllPlayerControls.Length; } } + public static string GetHudText() { return string.Format(Translator.GetString("KBTimeRemain"), RoundTime.ToString()); } + public static void OnPlayerAttack(PlayerControl killer, PlayerControl target) { if (killer == null || target == null || Options.CurrentGameMode != CustomGameMode.SoloKombat) return; @@ -242,6 +259,7 @@ internal static class SoloKombatManager Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: killer); Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: target); } + public static void OnPlayerBack(PlayerControl pc) { BackCountdown.Remove(pc.PlayerId); @@ -257,6 +275,7 @@ internal static class SoloKombatManager PlayerRandomSpwan(pc); } + public static void PlayerRandomSpwan(PlayerControl pc) { SpawnMap map; @@ -276,6 +295,7 @@ internal static class SoloKombatManager break; } } + public static void OnPlyaerDead(PlayerControl target) { originalSpeed.Remove(target.PlayerId); @@ -288,6 +308,7 @@ internal static class SoloKombatManager BackCountdown.TryAdd(target.PlayerId, KB_ResurrectionWaitingTime.GetInt()); SendRPCSyncKBBackCountdown(target); } + public static void OnPlayerKill(PlayerControl killer) { killer.KillFlash(); @@ -318,6 +339,7 @@ internal static class SoloKombatManager break; } } + public static void AddNameNotify(PlayerControl pc, string text, int time = 5) { NameNotify.Remove(pc.PlayerId); @@ -334,7 +356,8 @@ internal static class SoloKombatManager class FixedUpdatePatch { private static long LastFixedUpdate; - public static void Postfix(/*PlayerControl __instance*/) + + public static void Postfix( /*PlayerControl __instance*/) { if (!GameStates.IsInTask || Options.CurrentGameMode != CustomGameMode.SoloKombat) return; @@ -367,6 +390,7 @@ internal static class SoloKombatManager SendRPCSyncKBPlayer(pc.PlayerId); notifyRoles = true; } + // 复活玩家随机复活(二次确认) if (pc.SoloAlive() && !pc.inVent) { @@ -374,6 +398,7 @@ internal static class SoloKombatManager var dis = Vector2.Distance(pos, pc.Pos()); if (dis < 1.1f) PlayerRandomSpwan(pc); } + // 复活倒计时 if (BackCountdown.ContainsKey(pc.PlayerId)) { @@ -383,6 +408,7 @@ internal static class SoloKombatManager SendRPCSyncKBBackCountdown(pc); notifyRoles = true; } + // 清除过期的提示信息 if (NameNotify.ContainsKey(pc.PlayerId) && NameNotify[pc.PlayerId].TIMESTAMP < Utils.TimeStamp) { @@ -390,6 +416,7 @@ internal static class SoloKombatManager SendRPCSyncNameNotify(pc); notifyRoles = true; } + // 必要时刷新玩家名字 if (notifyRoles) Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); } diff --git a/Modules/AntiBlackout.cs b/Modules/AntiBlackout.cs index 08364dde5..754f2eb63 100644 --- a/Modules/AntiBlackout.cs +++ b/Modules/AntiBlackout.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Runtime.CompilerServices; using AmongUs.GameOptions; using Hazel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; using TOHE.Modules; -using TOHE.Roles.Neutral; namespace TOHE; @@ -14,26 +14,17 @@ public static class AntiBlackout ///Whether to override the ejection process /// public static bool OverrideExiledPlayer => IsRequired && (IsSingleImpostor || Diff_CrewImp == 1); + /// ///Is there only one impostor? /// public static bool IsSingleImpostor => Main.RealOptionsData != null ? Main.RealOptionsData.GetInt(Int32OptionNames.NumImpostors) <= 1 : Main.NormalOptions.NumImpostors <= 1; + /// ///Whether processing within AntiBlackout is required /// - public static bool IsRequired => Options.NoGameEnd.GetBool() - || Jackal.IsEnable || Pelican.IsEnable || Magician.IsEnable || Enderman.IsEnable - || Gamer.IsEnable || BloodKnight.IsEnable || WeaponMaster.IsEnable || SoulHunter.IsEnable - || Succubus.IsEnable || Poisoner.IsEnable || Reckless.IsEnable || Bubble.IsEnable - || Juggernaut.IsEnable || HeadHunter.IsEnable || Necromancer.IsEnable - || Ritualist.IsEnable || Virus.IsEnable || Vengeance.IsEnable || Doppelganger.IsEnable - || Wraith.IsEnable || HexMaster.IsEnable || Imitator.IsEnable() || Mycologist.IsEnable - || Traitor.IsEnable || Pickpocket.IsEnable || Werewolf.IsEnable || Sprayer.IsEnable - || NSerialKiller.IsEnable || RuthlessRomantic.IsEnable || Hookshot.IsEnable - || Maverick.IsEnable || Jinx.IsEnable || Eclipse.IsEnable || PlagueDoctor.IsEnable - || Medusa.IsEnable || Spiritcaller.IsEnable || Pyromaniac.IsEnable - || PlagueBearer.IsEnable || CustomRoles.Sidekick.RoleExist(true) - || CustomRoles.Pestilence.RoleExist(true); + public static bool IsRequired => Options.NoGameEnd.GetBool() || Main.AllPlayerControls.Any(x => x.GetCustomRole().GetCountTypes() is not CountTypes.Crew and not CountTypes.Impostor and not CountTypes.OutOfGame); + //|| Pirate.IsEnable; /// ///Difference between the number of non-impostors and the number of impostors @@ -49,21 +40,24 @@ public static class AntiBlackout if (pc.Data.Role.IsImpostor) numImpostors++; else numCrewmates++; } + return numCrewmates - numImpostors; } } + public static bool IsCached { get; private set; } private static Dictionary isDeadCache = []; - private readonly static LogHandler logger = Logger.Handler("AntiBlackout"); + private static readonly LogHandler Logger = TOHE.Logger.Handler("AntiBlackout"); public static void SetIsDead(bool doSend = true, [CallerMemberName] string callerMethodName = "") { - logger.Info($"SetIsDead is called from {callerMethodName}"); + Logger.Info($"SetIsDead is called from {callerMethodName}"); if (IsCached) { - logger.Info("Please run RestoreIsDead before running SetIsDead again."); + Logger.Info("Please run RestoreIsDead before running SetIsDead again."); return; } + isDeadCache.Clear(); foreach (var info in GameData.Instance.AllPlayers) { @@ -72,12 +66,14 @@ public static class AntiBlackout info.IsDead = false; info.Disconnected = false; } + IsCached = true; if (doSend) SendGameData(); } + public static void RestoreIsDead(bool doSend = true, [CallerMemberName] string callerMethodName = "") { - logger.Info($"RestoreIsDead is called from {callerMethodName}"); + Logger.Info($"RestoreIsDead is called from {callerMethodName}"); foreach (var info in GameData.Instance.AllPlayers) { if (info == null) continue; @@ -87,6 +83,7 @@ public static class AntiBlackout info.Disconnected = val.Disconnected; } } + isDeadCache.Clear(); IsCached = false; if (doSend) SendGameData(); @@ -94,7 +91,7 @@ public static class AntiBlackout public static void SendGameData([CallerMemberName] string callerMethodName = "") { - logger.Info($"SendGameData is called from {callerMethodName}"); + Logger.Info($"SendGameData is called from {callerMethodName}"); MessageWriter writer = MessageWriter.Get(SendOption.Reliable); // {} is for readability. writer.StartMessage(5); //0x05 GameData @@ -112,6 +109,7 @@ public static class AntiBlackout AmongUsClient.Instance.SendOrDisconnect(writer); writer.Recycle(); } + public static void OnDisconnect(GameData.PlayerInfo player) { // Execution conditions: client is host, IsDead is overwritten, player is disconnected @@ -121,13 +119,14 @@ public static class AntiBlackout SendGameData(); } +/* /// ///Run the code with IsDead temporarily restored to its original value ///Execution details /// public static void TempRestore(Action action) { - logger.Info("==Temp Restore=="); + Logger.Info("==Temp Restore=="); //Whether TempRestore was executed with IsDead overwritten bool before_IsCached = IsCached; try @@ -137,19 +136,20 @@ public static class AntiBlackout } catch (Exception ex) { - logger.Warn("An exception occurred within AntiBlackout.TempRestore"); - logger.Exception(ex); + Logger.Warn("An exception occurred within AntiBlackout.TempRestore"); + Logger.Exception(ex); } finally { if (before_IsCached) SetIsDead(doSend: false); - logger.Info("==/Temp Restore=="); + Logger.Info("==/Temp Restore=="); } } +*/ public static void Reset() { - logger.Info("==Reset=="); + Logger.Info("==Reset=="); isDeadCache ??= []; isDeadCache.Clear(); IsCached = false; diff --git a/Modules/BanManager.cs b/Modules/BanManager.cs index 274512059..477c11b8c 100644 --- a/Modules/BanManager.cs +++ b/Modules/BanManager.cs @@ -1,210 +1,225 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using HarmonyLib; -using InnerNet; -using static TOHE.Translator; - -namespace TOHE; - -public static class BanManager -{ - private static readonly string DENY_NAME_LIST_PATH = @"./TOHE_DATA/DenyName.txt"; - private static readonly string BAN_LIST_PATH = @"./TOHE_DATA/BanList.txt"; - private static readonly string MODERATOR_LIST_PATH = @"./TOHE_DATA/Moderators.txt"; +using HarmonyLib; +using InnerNet; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using static TOHE.Translator; + +namespace TOHE; + +public static class BanManager +{ + private static readonly string DENY_NAME_LIST_PATH = @"./TOHE_DATA/DenyName.txt"; + private static readonly string BAN_LIST_PATH = @"./TOHE_DATA/BanList.txt"; + private static readonly string MODERATOR_LIST_PATH = @"./TOHE_DATA/Moderators.txt"; private static readonly string WHITE_LIST_LIST_PATH = @"./TOHE_DATA/WhiteList.txt"; #pragma warning disable IDE0044 // Add readonly modifier private static List EACList = []; // Don't make it read-only #pragma warning restore IDE0044 // Add readonly modifier - public static List TempBanWhiteList = []; //To prevent writing to ban list - public static void Init() - { - try - { - Directory.CreateDirectory("TOHE_DATA"); - - if (!File.Exists(BAN_LIST_PATH)) - { - Logger.Warn("Create a new BanList.txt file", "BanManager"); - File.Create(BAN_LIST_PATH).Close(); - } - if (!File.Exists(DENY_NAME_LIST_PATH)) - { - Logger.Warn("Create a new DenyName.txt file", "BanManager"); - File.Create(DENY_NAME_LIST_PATH).Close(); - File.WriteAllText(DENY_NAME_LIST_PATH, GetResourcesTxt("TOHE.Resources.Config.DenyName.txt")); - } - if (!File.Exists(MODERATOR_LIST_PATH)) - { - Logger.Warn("Creating a new Moderators.txt file", "BanManager"); - File.Create(MODERATOR_LIST_PATH).Close(); - } - if (!File.Exists(WHITE_LIST_LIST_PATH)) - { - Logger.Warn("Creating a new WhiteList.txt file", "BanManager"); - File.Create(WHITE_LIST_LIST_PATH).Close(); - } - - // Read EAC List - var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("TOHE.Resources.Config.EACList.txt"); - stream.Position = 0; - using StreamReader sr = new(stream, Encoding.UTF8); - string line; - while ((line = sr.ReadLine()) != null) - { - if (line == "" || line.StartsWith("#")) continue; - EACList.Add(line); - } - - } - catch (Exception ex) - { - Logger.Exception(ex, "BanManager"); - } - } - private static string GetResourcesTxt(string path) - { - var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path); - stream.Position = 0; - using StreamReader reader = new(stream, Encoding.UTF8); - return reader.ReadToEnd(); - } - public static string GetHashedPuid(this ClientData player) - { - if (player == null) return ""; - string puid = player.ProductUserId; + public static List TempBanWhiteList = []; //To prevent writing to ban list + + public static void Init() + { + try + { + Directory.CreateDirectory("TOHE_DATA"); + + if (!File.Exists(BAN_LIST_PATH)) + { + Logger.Warn("Create a new BanList.txt file", "BanManager"); + File.Create(BAN_LIST_PATH).Close(); + } + + if (!File.Exists(DENY_NAME_LIST_PATH)) + { + Logger.Warn("Create a new DenyName.txt file", "BanManager"); + File.Create(DENY_NAME_LIST_PATH).Close(); + File.WriteAllText(DENY_NAME_LIST_PATH, GetResourcesTxt("TOHE.Resources.Config.DenyName.txt")); + } + + if (!File.Exists(MODERATOR_LIST_PATH)) + { + Logger.Warn("Creating a new Moderators.txt file", "BanManager"); + File.Create(MODERATOR_LIST_PATH).Close(); + } + + if (!File.Exists(WHITE_LIST_LIST_PATH)) + { + Logger.Warn("Creating a new WhiteList.txt file", "BanManager"); + File.Create(WHITE_LIST_LIST_PATH).Close(); + } + + // Read EAC List + var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("TOHE.Resources.Config.EACList.txt"); + stream.Position = 0; + using StreamReader sr = new(stream, Encoding.UTF8); + string line; + while ((line = sr.ReadLine()) != null) + { + if (line == "" || line.StartsWith("#")) continue; + EACList.Add(line); + } + } + catch (Exception ex) + { + Logger.Exception(ex, "BanManager"); + } + } + + private static string GetResourcesTxt(string path) + { + var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path); + stream.Position = 0; + using StreamReader reader = new(stream, Encoding.UTF8); + return reader.ReadToEnd(); + } + + public static string GetHashedPuid(this ClientData player) + { + if (player == null) return ""; + string puid = player.ProductUserId; using SHA256 sha256 = SHA256.Create(); // get sha-256 hash byte[] sha256Bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(puid)); string sha256Hash = BitConverter.ToString(sha256Bytes).Replace("-", "").ToLower(); // pick front 5 and last 4 - return string.Concat(sha256Hash.AsSpan(0, 5), sha256Hash.AsSpan(sha256Hash.Length - 4)); - } - public static void AddBanPlayer(ClientData player) - { - if (!AmongUsClient.Instance.AmHost || player == null) return; - if (!CheckBanList(player?.FriendCode, player?.GetHashedPuid()) && !TempBanWhiteList.Contains(player?.GetHashedPuid())) - { - if (player?.GetHashedPuid() != "" && player?.GetHashedPuid() != null && player?.GetHashedPuid() != "e3b0cb855") - { - File.AppendAllText(BAN_LIST_PATH, $"{player.FriendCode},{player?.GetHashedPuid()},{player.PlayerName.RemoveHtmlTags()}\n"); - Logger.SendInGame(string.Format(GetString("Message.AddedPlayerToBanList"), player.PlayerName)); - } - else Logger.Info($"Failed to add player {player?.PlayerName.RemoveHtmlTags()}/{player?.FriendCode}/{player?.GetHashedPuid()} to ban list!", "AddBanPlayer"); - } + return string.Concat(sha256Hash.AsSpan(0, 5), sha256Hash.AsSpan(sha256Hash.Length - 4)); } - public static void CheckDenyNamePlayer(ClientData player) - { - if (!AmongUsClient.Instance.AmHost || !Options.ApplyDenyNameList.GetBool()) return; - try - { - Directory.CreateDirectory("TOHE_DATA"); - if (!File.Exists(DENY_NAME_LIST_PATH)) File.Create(DENY_NAME_LIST_PATH).Close(); - using StreamReader sr = new(DENY_NAME_LIST_PATH); - string line; - while ((line = sr.ReadLine()) != null) - { - if (line == "") continue; - if (line.Contains("Amogus")) - { - AmongUsClient.Instance.KickPlayer(player.Id, false); - Logger.SendInGame(string.Format(GetString("Message.KickedByDenyName"), player.PlayerName, line)); - Logger.Info($"{player.PlayerName}は名前が「{line}」に一致したためキックされました。", "Kick"); - return; - } - if (line.Contains("Amogus V")) - { - AmongUsClient.Instance.KickPlayer(player.Id, false); - Logger.SendInGame(string.Format(GetString("Message.KickedByDenyName"), player.PlayerName, line)); - Logger.Info($"{player.PlayerName}は名前が「{line}」に一致したためキックされました。", "Kick"); - return; - } - - if (Regex.IsMatch(player.PlayerName, line)) - { - AmongUsClient.Instance.KickPlayer(player.Id, false); - Logger.SendInGame(string.Format(GetString("Message.KickedByDenyName"), player.PlayerName, line)); - Logger.Info($"{player.PlayerName}は名前が「{line}」に一致したためキックされました。", "Kick"); - return; - } - } - } - catch (Exception ex) - { - Logger.Exception(ex, "CheckDenyNamePlayer"); - } - } - public static void CheckBanPlayer(ClientData player) - { - if (!AmongUsClient.Instance.AmHost || !Options.ApplyBanList.GetBool()) return; - if (CheckBanList(player?.FriendCode, player?.GetHashedPuid())) - { - AmongUsClient.Instance.KickPlayer(player.Id, true); - Logger.SendInGame(string.Format(GetString("Message.BanedByBanList"), player.PlayerName)); - Logger.Info($"{player.PlayerName}は過去にBAN済みのためBANされました。", "BAN"); - return; - } - if (CheckEACList(player?.FriendCode, player?.GetHashedPuid())) - { - AmongUsClient.Instance.KickPlayer(player.Id, true); - Logger.SendInGame(string.Format(GetString("Message.BanedByEACList"), player.PlayerName)); - Logger.Info($"{player.PlayerName}存在于EAC封禁名单", "BAN"); - return; - } - if (TempBanWhiteList.Contains(player?.GetHashedPuid())) - { - AmongUsClient.Instance.KickPlayer(player.Id, true); - //This should not happen - Logger.Info($"{player.PlayerName} was in temp ban list", "BAN"); - } - } - public static bool CheckBanList(string code, string hashedpuid = "") - { - bool OnlyCheckPuid = false; - if (code == "" && hashedpuid != "") OnlyCheckPuid = true; - else if (code == "") return false; - try - { - Directory.CreateDirectory("TOHE_DATA"); - if (!File.Exists(BAN_LIST_PATH)) File.Create(BAN_LIST_PATH).Close(); - using StreamReader sr = new(BAN_LIST_PATH); - string line; - while ((line = sr.ReadLine()) != null) - { - if (line == "") continue; - if (!OnlyCheckPuid) - if (line.Contains(code)) return true; - if (line.Contains(hashedpuid)) return true; - } - } - catch (Exception ex) - { - Logger.Exception(ex, "CheckBanList"); - } - return false; - } - public static bool CheckEACList(string code, string hashedPuid) - { - bool OnlyCheckPuid = false; - if (code == "" && hashedPuid == "") OnlyCheckPuid = true; - else if (code == "") return false; - return EACList.Any(x => x.Contains(code) && !OnlyCheckPuid) || EACList.Any(x => x.Contains(hashedPuid) && hashedPuid != ""); - } -} -[HarmonyPatch(typeof(BanMenu), nameof(BanMenu.Select))] -class BanMenuSelectPatch -{ - public static void Postfix(BanMenu __instance, int clientId) - { - ClientData recentClient = AmongUsClient.Instance.GetRecentClient(clientId); - if (recentClient == null) return; - if (!BanManager.CheckBanList(recentClient?.FriendCode, recentClient?.GetHashedPuid())) __instance.BanButton.GetComponent().SetEnabledColors(); - } + public static void AddBanPlayer(ClientData player) + { + if (!AmongUsClient.Instance.AmHost || player == null) return; + if (!CheckBanList(player?.FriendCode, player?.GetHashedPuid()) && !TempBanWhiteList.Contains(player?.GetHashedPuid())) + { + if (player?.GetHashedPuid() != "" && player?.GetHashedPuid() != null && player?.GetHashedPuid() != "e3b0cb855") + { + File.AppendAllText(BAN_LIST_PATH, $"{player.FriendCode},{player?.GetHashedPuid()},{player.PlayerName.RemoveHtmlTags()}\n"); + Logger.SendInGame(string.Format(GetString("Message.AddedPlayerToBanList"), player.PlayerName)); + } + else Logger.Info($"Failed to add player {player?.PlayerName.RemoveHtmlTags()}/{player?.FriendCode}/{player?.GetHashedPuid()} to ban list!", "AddBanPlayer"); + } + } + + public static void CheckDenyNamePlayer(ClientData player) + { + if (!AmongUsClient.Instance.AmHost || !Options.ApplyDenyNameList.GetBool()) return; + try + { + Directory.CreateDirectory("TOHE_DATA"); + if (!File.Exists(DENY_NAME_LIST_PATH)) File.Create(DENY_NAME_LIST_PATH).Close(); + using StreamReader sr = new(DENY_NAME_LIST_PATH); + string line; + while ((line = sr.ReadLine()) != null) + { + if (line == "") continue; + if (line.Contains("Amogus")) + { + AmongUsClient.Instance.KickPlayer(player.Id, false); + Logger.SendInGame(string.Format(GetString("Message.KickedByDenyName"), player.PlayerName, line)); + Logger.Info($"{player.PlayerName}は名前が「{line}」に一致したためキックされました。", "Kick"); + return; + } + + if (line.Contains("Amogus V")) + { + AmongUsClient.Instance.KickPlayer(player.Id, false); + Logger.SendInGame(string.Format(GetString("Message.KickedByDenyName"), player.PlayerName, line)); + Logger.Info($"{player.PlayerName}は名前が「{line}」に一致したためキックされました。", "Kick"); + return; + } + + if (Regex.IsMatch(player.PlayerName, line)) + { + AmongUsClient.Instance.KickPlayer(player.Id, false); + Logger.SendInGame(string.Format(GetString("Message.KickedByDenyName"), player.PlayerName, line)); + Logger.Info($"{player.PlayerName}は名前が「{line}」に一致したためキックされました。", "Kick"); + return; + } + } + } + catch (Exception ex) + { + Logger.Exception(ex, "CheckDenyNamePlayer"); + } + } + + public static void CheckBanPlayer(ClientData player) + { + if (!AmongUsClient.Instance.AmHost || !Options.ApplyBanList.GetBool()) return; + if (CheckBanList(player?.FriendCode, player?.GetHashedPuid())) + { + AmongUsClient.Instance.KickPlayer(player.Id, true); + Logger.SendInGame(string.Format(GetString("Message.BanedByBanList"), player.PlayerName)); + Logger.Info($"{player.PlayerName}は過去にBAN済みのためBANされました。", "BAN"); + return; + } + + if (CheckEACList(player?.FriendCode, player?.GetHashedPuid())) + { + AmongUsClient.Instance.KickPlayer(player.Id, true); + Logger.SendInGame(string.Format(GetString("Message.BanedByEACList"), player.PlayerName)); + Logger.Info($"{player.PlayerName}存在于EAC封禁名单", "BAN"); + return; + } + + if (TempBanWhiteList.Contains(player?.GetHashedPuid())) + { + AmongUsClient.Instance.KickPlayer(player.Id, true); + //This should not happen + Logger.Info($"{player.PlayerName} was in temp ban list", "BAN"); + } + } + + public static bool CheckBanList(string code, string hashedpuid = "") + { + bool OnlyCheckPuid = false; + if (code == "" && hashedpuid != "") OnlyCheckPuid = true; + else if (code == "") return false; + try + { + Directory.CreateDirectory("TOHE_DATA"); + if (!File.Exists(BAN_LIST_PATH)) File.Create(BAN_LIST_PATH).Close(); + using StreamReader sr = new(BAN_LIST_PATH); + string line; + while ((line = sr.ReadLine()) != null) + { + if (line == "") continue; + if (!OnlyCheckPuid) + if (line.Contains(code)) + return true; + if (line.Contains(hashedpuid)) return true; + } + } + catch (Exception ex) + { + Logger.Exception(ex, "CheckBanList"); + } + + return false; + } + + public static bool CheckEACList(string code, string hashedPuid) + { + bool OnlyCheckPuid = false; + if (code == "" && hashedPuid == "") OnlyCheckPuid = true; + else if (code == "") return false; + return EACList.Any(x => x.Contains(code) && !OnlyCheckPuid) || EACList.Any(x => x.Contains(hashedPuid) && hashedPuid != ""); + } +} + +[HarmonyPatch(typeof(BanMenu), nameof(BanMenu.Select))] +class BanMenuSelectPatch +{ + public static void Postfix(BanMenu __instance, int clientId) + { + ClientData recentClient = AmongUsClient.Instance.GetRecentClient(clientId); + if (recentClient == null) return; + if (!BanManager.CheckBanList(recentClient?.FriendCode, recentClient?.GetHashedPuid())) __instance.BanButton.GetComponent().SetEnabledColors(); + } } \ No newline at end of file diff --git a/Modules/Camouflague.cs b/Modules/Camouflague.cs index 2507abe83..ef162b4ea 100644 --- a/Modules/Camouflague.cs +++ b/Modules/Camouflague.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; using AmongUs.Data; +using System.Collections.Generic; +using System.Linq; using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; @@ -18,20 +19,22 @@ static class PlayerOutfitExtension instance.NamePlateId = nameplateId; return instance; } + public static bool Compare(this GameData.PlayerOutfit instance, GameData.PlayerOutfit targetOutfit) { return instance.ColorId == targetOutfit.ColorId && - instance.HatId == targetOutfit.HatId && - instance.SkinId == targetOutfit.SkinId && - instance.VisorId == targetOutfit.VisorId && - instance.PetId == targetOutfit.PetId; - + instance.HatId == targetOutfit.HatId && + instance.SkinId == targetOutfit.SkinId && + instance.VisorId == targetOutfit.VisorId && + instance.PetId == targetOutfit.PetId; } + public static string GetString(this GameData.PlayerOutfit instance) { return $"{instance.PlayerName} Color:{instance.ColorId} {instance.HatId} {instance.SkinId} {instance.VisorId} {instance.PetId}"; } } + public static class Camouflage { static GameData.PlayerOutfit CamouflageOutfit = new GameData.PlayerOutfit().Set("", 15, "", "", "", "", ""); // Default @@ -103,9 +106,10 @@ public static class Camouflage CamouflageOutfit.PetId = petId; } } + public static void CheckCamouflage() { - if (!(AmongUsClient.Instance.AmHost && (Options.CommsCamouflage.GetBool() || Camouflager.IsEnable))) return; + if (!(AmongUsClient.Instance.AmHost && (Options.CommsCamouflage.GetBool() || Main.PlayerStates.Any(x => x.Value.Role is Camouflager { IsEnable: true })))) return; var oldIsCamouflage = IsCamouflage; @@ -122,12 +126,14 @@ public static class Camouflage PetsPatch.RpcRemovePet(pc); } } + Utils.NotifyRoles(NoCache: true); } } + public static void RpcSetSkin(PlayerControl target, bool ForceRevert = false, bool RevertToDefault = false, bool GameEnd = false) { - if (!(AmongUsClient.Instance.AmHost && (Options.CommsCamouflage.GetBool() || Camouflager.IsEnable))) return; + if (!(AmongUsClient.Instance.AmHost && (Options.CommsCamouflage.GetBool() || Main.PlayerStates.Any(x => x.Value.Role is Camouflager { IsEnable: true })))) return; if (target == null) return; var id = target.PlayerId; @@ -148,6 +154,7 @@ public static class Camouflage //シェイプシフターなら今の姿のidに変更 id = Main.ShapeshiftTarget[id]; } + if (!GameEnd && Doppelganger.DoppelPresentSkin.TryGetValue(id, out GameData.PlayerOutfit value)) newOutfit = value; else { @@ -156,9 +163,11 @@ public static class Camouflage var dpc = Utils.GetPlayerById(id); dpc?.RpcSetName(value1); } + newOutfit = PlayerSkins[id]; } } + // if the current Outfit is the same, return it if (newOutfit.Compare(target.Data.DefaultOutfit)) return; diff --git a/Modules/ClientOptionItem.cs b/Modules/ClientOptionItem.cs index eec3bea35..d28760c41 100644 --- a/Modules/ClientOptionItem.cs +++ b/Modules/ClientOptionItem.cs @@ -1,5 +1,5 @@ -using System; -using BepInEx.Configuration; +using BepInEx.Configuration; +using System; using UnityEngine; using Object = UnityEngine.Object; diff --git a/Modules/Cloud.cs b/Modules/Cloud.cs index a1d373345..0979c628a 100644 --- a/Modules/Cloud.cs +++ b/Modules/Cloud.cs @@ -1,20 +1,23 @@ -using System; +using HarmonyLib; +using System; using System.IO; using System.Net.Sockets; using System.Reflection; using System.Text; -using HarmonyLib; namespace TOHE; internal class Cloud { private static string IP; + //private static int LOBBY_PORT = 0; private static int EAC_PORT; + //private static Socket ClientSocket; private static Socket EacClientSocket; private static long LastRepotTimeStamp; + public static void Init() { try @@ -30,6 +33,7 @@ internal class Cloud Logger.Exception(e, "Cloud Init"); } } + private static string GetResourcesTxt(string path) { var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path); @@ -72,6 +76,7 @@ internal class Cloud }*/ private static bool connecting; + public static void StartConnect() { if (connecting || (EacClientSocket != null && EacClientSocket.Connected)) return; @@ -83,6 +88,7 @@ internal class Cloud connecting = false; return; } + try { if (IP == null || EAC_PORT == 0) throw new("Has no ip or port"); @@ -97,14 +103,17 @@ internal class Cloud Logger.Exception(e, "EAC Cloud"); throw; } + connecting = false; }, 3.5f, "EAC Cloud Connect"); } + public static void StopConnect() { if (EacClientSocket != null && EacClientSocket.Connected) EacClientSocket.Close(); } + public static void SendData(string msg) { StartConnect(); @@ -113,8 +122,10 @@ internal class Cloud Logger.Warn("未连接至TOHE服务器,报告被取消", "EAC Cloud"); return; } + EacClientSocket.Send(Encoding.Default.GetBytes(msg)); } + [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))] class EACConnectTimeOut { diff --git a/Modules/CustomRoleSelector.cs b/Modules/CustomRoleSelector.cs index 98df3c4a2..e36ed63bc 100644 --- a/Modules/CustomRoleSelector.cs +++ b/Modules/CustomRoleSelector.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using HarmonyLib; +using System.Collections.Generic; +using System.Linq; using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; @@ -26,9 +26,11 @@ public static class ShuffleListExtension int k = random.Next(n + 1); (list[n], list[k]) = (list[k], list[n]); } + return list; } } + internal class CustomRoleSelector { public static Dictionary RoleResult; @@ -44,10 +46,29 @@ internal class CustomRoleSelector public class RoleAssignInfo(CustomRoles role, int spawnChance, int maxCount, int assignedCount = 0) { - public CustomRoles Role { get => role; set => role = value; } - public int SpawnChance { get => spawnChance; set => spawnChance = value; } - public int MaxCount { get => maxCount; set => maxCount = value; } - public int AssignedCount { get => assignedCount; set => assignedCount = value; } + public CustomRoles Role + { + get => role; + set => role = value; + } + + public int SpawnChance + { + get => spawnChance; + set => spawnChance = value; + } + + public int MaxCount + { + get => maxCount; + set => maxCount = value; + } + + public int AssignedCount + { + get => assignedCount; + set => assignedCount = value; + } } public static void GetNeutralCounts(int NKmaxOpt, int NKminOpt, int NNKmaxOpt, int NNKminOpt, ref int ResultNKnum, ref int ResultNNKnum) @@ -75,6 +96,7 @@ internal class CustomRoleSelector { RoleResult.Add(pc, CustomRoles.KB_Normal); } + return; case CustomGameMode.FFA: RoleResult = []; @@ -82,6 +104,7 @@ internal class CustomRoleSelector { RoleResult.Add(pc, CustomRoles.Killer); } + return; case CustomGameMode.MoveAndStop: RoleResult = []; @@ -89,6 +112,7 @@ internal class CustomRoleSelector { RoleResult.Add(pc, CustomRoles.Tasker); } + return; case CustomGameMode.HotPotato: RoleResult = []; @@ -96,6 +120,7 @@ internal class CustomRoleSelector { RoleResult.Add(pc, CustomRoles.Potato); } + return; } @@ -307,7 +332,9 @@ internal class CustomRoleSelector Imps = ImpRoleCounts; - if (info.AssignedCount >= info.MaxCount) while (ChanceImpRoles.Contains(selected)) ChanceImpRoles.Remove(selected); + if (info.AssignedCount >= info.MaxCount) + while (ChanceImpRoles.Contains(selected)) + ChanceImpRoles.Remove(selected); if (readyRoleNum >= playerCount) goto EndOfAssign; if (readyImpNum >= optImpNum) break; @@ -384,7 +411,9 @@ internal class CustomRoleSelector NNKs = NNKRoleCounts; - if (info.AssignedCount >= info.MaxCount) while (ChanceNNKRoles.Contains(selected)) ChanceNNKRoles.Remove(selected); + if (info.AssignedCount >= info.MaxCount) + while (ChanceNNKRoles.Contains(selected)) + ChanceNNKRoles.Remove(selected); if (readyRoleNum >= playerCount) goto EndOfAssign; if (readyNonNeutralKillingNum >= optNonNeutralKillingNum) break; @@ -459,7 +488,9 @@ internal class CustomRoleSelector NKs = NKRoleCounts; - if (info.AssignedCount >= info.MaxCount) while (ChanceNKRoles.Contains(selected)) ChanceNKRoles.Remove(selected); + if (info.AssignedCount >= info.MaxCount) + while (ChanceNKRoles.Contains(selected)) + ChanceNKRoles.Remove(selected); if (readyRoleNum >= playerCount) goto EndOfAssign; if (readyNeutralKillingNum >= optNeutralKillingNum) break; @@ -532,7 +563,9 @@ internal class CustomRoleSelector Crews = CrewRoleCounts; - if (info.AssignedCount >= info.MaxCount) while (ChanceCrewRoles.Contains(selected)) ChanceCrewRoles.Remove(selected); + if (info.AssignedCount >= info.MaxCount) + while (ChanceCrewRoles.Contains(selected)) + ChanceCrewRoles.Remove(selected); if (readyRoleNum >= playerCount) goto EndOfAssign; } @@ -550,12 +583,6 @@ internal class CustomRoleSelector if (rd.Next(0, 100) < Sans.BardChance.GetInt() && FinalRolesList.Remove(CustomRoles.Sans)) FinalRolesList.Add(CustomRoles.Bard); if (rd.Next(0, 100) < Options.NukerChance.GetInt() && FinalRolesList.Remove(CustomRoles.Bomber)) FinalRolesList.Add(CustomRoles.Nuker); - if (Romantic.IsEnable) - { - if (FinalRolesList.Contains(CustomRoles.Romantic) && FinalRolesList.Contains(CustomRoles.Lovers)) - FinalRolesList.Remove(CustomRoles.Lovers); - } - Logger.Info(string.Join(", ", FinalRolesList.Select(x => x.ToString())), "RoleResults"); while (AllPlayers.Count > 0 && FinalRolesList.Count > 0) @@ -583,6 +610,7 @@ internal class CustomRoleSelector public static int addScientistNum; public static int addEngineerNum; public static int addShapeshifterNum; + public static void CalculateVanillaRoleCount() { // Calculate the number of base roles @@ -607,6 +635,7 @@ internal class CustomRoleSelector } public static List AddonRolesList = []; + public static void SelectAddonRoles() { if (Options.CurrentGameMode is CustomGameMode.SoloKombat or CustomGameMode.FFA or CustomGameMode.MoveAndStop) return; diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index d726d8aa8..6d67e31e1 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -221,9 +221,9 @@ internal static class CustomRolesHelper CustomRoles.Provocateur => new Provocateur(), CustomRoles.Pursuer => new Pursuer(), CustomRoles.Pyromaniac => new Pyromaniac(), - CustomRoles.Reckless => new Sans(), + CustomRoles.Reckless => new Sans(), // Use the same code as Sans with small modifications CustomRoles.Revolutionist => new Revolutionist(), - CustomRoles.Ritualist => new Ritualist(), + CustomRoles.Ritualist => new EvilDiviner(), // Use the same code as EvilDiviner with small modifications CustomRoles.Romantic => new Romantic(), CustomRoles.RuthlessRomantic => new RuthlessRomantic(), CustomRoles.NSerialKiller => new NSerialKiller(), @@ -281,7 +281,7 @@ internal static class CustomRolesHelper CustomRoles.Agitater => CustomRoles.Impostor, CustomRoles.ImpostorTOHE => CustomRoles.Impostor, CustomRoles.EvilDiviner => CustomRoles.Impostor, - CustomRoles.Wildling => Wildling.CanShapeshift.GetBool() ? CustomRoles.Shapeshifter : CustomRoles.Impostor, + CustomRoles.Wildling => Wildling.CanShapeshiftOpt.GetBool() ? CustomRoles.Shapeshifter : CustomRoles.Impostor, CustomRoles.Morphling => CustomRoles.Shapeshifter, CustomRoles.Warlock => CustomRoles.Impostor, CustomRoles.SerialKiller => CustomRoles.Impostor, @@ -902,6 +902,8 @@ internal static class CustomRolesHelper CustomRoles.Witness when Options.WitnessUsePet.GetBool() => true, CustomRoles.Refugee => true, + CustomRoles.Necromancer => true, + CustomRoles.Deathknight => true, _ => false, }; diff --git a/Modules/CustomRpcSender.cs b/Modules/CustomRpcSender.cs index 8736d4fd2..dacfb10ce 100644 --- a/Modules/CustomRpcSender.cs +++ b/Modules/CustomRpcSender.cs @@ -1,9 +1,9 @@ -using System; -using System.Diagnostics.CodeAnalysis; using AmongUs.GameOptions; using Hazel; using Il2CppInterop.Runtime.InteropTypes.Arrays; using InnerNet; +using System; +using System.Diagnostics.CodeAnalysis; namespace TOHE; diff --git a/Modules/CustomSounds.cs b/Modules/CustomSounds.cs index bdc7aaccd..7641396af 100644 --- a/Modules/CustomSounds.cs +++ b/Modules/CustomSounds.cs @@ -1,8 +1,8 @@ -using System; +using Hazel; +using System; using System.IO; using System.Reflection; using System.Runtime.InteropServices; -using Hazel; namespace TOHE.Modules; @@ -10,16 +10,20 @@ public static class CustomSoundsManager { public static void RPCPlayCustomSound(this PlayerControl pc, string sound, bool force = false) { - if (!force) if (!AmongUsClient.Instance.AmHost || !pc.IsModClient()) return; + if (!force) + if (!AmongUsClient.Instance.AmHost || !pc.IsModClient()) + return; if (pc == null || PlayerControl.LocalPlayer.PlayerId == pc.PlayerId) { Play(sound); return; } + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.PlayCustomSound, SendOption.Reliable, pc.GetClientId()); writer.Write(sound); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void RPCPlayCustomSoundAll(string sound) { if (!AmongUsClient.Instance.AmHost) return; @@ -28,10 +32,12 @@ public static class CustomSoundsManager AmongUsClient.Instance.FinishRpcImmediately(writer); Play(sound); } + public static void ReceiveRPC(MessageReader reader) => Play(reader.ReadString()); private static readonly string SOUNDS_PATH = @$"{Environment.CurrentDirectory.Replace(@"\", "/")}/BepInEx/resources/"; + public static void Play(string sound) { if (!Constants.ShouldPlaySfx() || !Main.EnableCustomSoundEffect.Value) return; @@ -48,10 +54,12 @@ public static class CustomSoundsManager Logger.Warn($"声音文件缺失:{sound}", "CustomSounds"); return; } + var fs = File.Create(path); stream.CopyTo(fs); fs.Close(); } + StartPlay(path); Logger.Msg($"Playing sound:{sound}", "CustomSounds"); } @@ -63,5 +71,4 @@ public static class CustomSoundsManager public static extern bool PlaySound(string Filename, int Mod, int Flags); #pragma warning restore CA1401 // P/Invokes should not be visible public static void StartPlay(string path) => PlaySound(@$"{path}", 0, 1); //第3个形参,把1换为9,连续播放 - -} +} \ No newline at end of file diff --git a/Modules/CustomWinnerHolder.cs b/Modules/CustomWinnerHolder.cs index 0c2a614c4..06229fa9a 100644 --- a/Modules/CustomWinnerHolder.cs +++ b/Modules/CustomWinnerHolder.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using Hazel; +using System.Collections.Generic; namespace TOHE; @@ -9,12 +9,15 @@ public static class CustomWinnerHolder // Used to determine background color of results, etc. // Note: When changing this variable, if you do not change WinnerRoles and WinnerIds at the same time, unexpected winners may appear. public static CustomWinner WinnerTeam; + // Stores the team of additional winning players. // Used to display results. public static HashSet AdditionalWinnerTeams; + // The winning role is stored, and all players whose roles are stored in this variable win. // Ideal for handling team neutrals. public static HashSet WinnerRoles; + // Stores the winner's PlayerID, all players with this ID win. // Ideal for handling neutrals that win alone. public static HashSet WinnerIds; @@ -26,17 +29,20 @@ public static class CustomWinnerHolder WinnerRoles = []; WinnerIds = []; } + public static void ClearWinners() { WinnerRoles.Clear(); WinnerIds.Clear(); } + /// Assign a value to WinnerTeam. Add to AdditionalWinnerTeams if already assigned. public static void SetWinnerOrAdditonalWinner(CustomWinner winner) { if (WinnerTeam == CustomWinner.Default) WinnerTeam = winner; else AdditionalWinnerTeams.Add((AdditionalWinners)winner); } + /// Assign a value to WinnerTeam. If it is already assigned, add the existing value to AdditionalWinnerTeams and then assign it. public static void ShiftWinnerAndSetWinner(CustomWinner winner) { @@ -44,6 +50,7 @@ public static class CustomWinnerHolder AdditionalWinnerTeams.Add((AdditionalWinners)WinnerTeam); WinnerTeam = winner; } + /// Delete any existing values and then assign the values to WinnerTeam. public static void ResetAndSetWinner(CustomWinner winner) { @@ -69,6 +76,7 @@ public static class CustomWinnerHolder return writer; } + public static void ReadFrom(MessageReader reader) { WinnerTeam = (CustomWinner)reader.ReadPackedInt32(); diff --git a/Modules/DisableDevice.cs b/Modules/DisableDevice.cs index 6ed4e6817..017a8e525 100644 --- a/Modules/DisableDevice.cs +++ b/Modules/DisableDevice.cs @@ -1,6 +1,6 @@ +using HarmonyLib; using System; using System.Collections.Generic; -using HarmonyLib; using UnityEngine; using Object = UnityEngine.Object; @@ -12,6 +12,7 @@ class DisableDevice public static bool DoDisable => Options.DisableDevices.GetBool(); private static readonly List DesyncComms = []; private static int frame; + public static readonly Dictionary DevicePos = new() { ["SkeldAdmin"] = new(3.48f, -8.62f), @@ -31,6 +32,7 @@ class DisableDevice ["FungleCamera"] = new(6.20f, 0.10f), ["FungleVital"] = new(-2.50f, -9.80f) }; + public static float UsableDistance() { return (MapNames)Main.NormalOptions.MapId switch @@ -44,6 +46,7 @@ class DisableDevice _ => 0.0f }; } + public static void FixedUpdate() { frame = frame == 3 ? 0 : ++frame; @@ -85,6 +88,7 @@ class DisableDevice doComms |= Vector2.Distance(PlayerPos, DevicePos["PolusLeftAdmin"]) <= UsableDistance(); doComms |= Vector2.Distance(PlayerPos, DevicePos["PolusRightAdmin"]) <= UsableDistance(); } + if (Options.DisablePolusCamera.GetBool()) doComms |= Vector2.Distance(PlayerPos, DevicePos["PolusCamera"]) <= UsableDistance(); if (Options.DisablePolusVital.GetBool()) @@ -114,6 +118,7 @@ class DisableDevice break; } } + doComms &= !ignore; if (doComms && !pc.inVent) { @@ -138,6 +143,7 @@ class DisableDevice } } } + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.Start))] public class RemoveDisableDevicesPatch { @@ -151,11 +157,11 @@ public class RemoveDisableDevicesPatch { var player = PlayerControl.LocalPlayer; bool ignore = player.Is(CustomRoles.GM) || - !player.IsAlive() || - (Options.DisableDevicesIgnoreImpostors.GetBool() && player.Is(CustomRoleTypes.Impostor)) || - (Options.DisableDevicesIgnoreNeutrals.GetBool() && player.Is(CustomRoleTypes.Neutral)) || - (Options.DisableDevicesIgnoreCrewmates.GetBool() && player.Is(CustomRoleTypes.Crewmate)) || - (Options.DisableDevicesIgnoreAfterAnyoneDied.GetBool() && GameStates.AlreadyDied); + !player.IsAlive() || + (Options.DisableDevicesIgnoreImpostors.GetBool() && player.Is(CustomRoleTypes.Impostor)) || + (Options.DisableDevicesIgnoreNeutrals.GetBool() && player.Is(CustomRoleTypes.Neutral)) || + (Options.DisableDevicesIgnoreCrewmates.GetBool() && player.Is(CustomRoleTypes.Crewmate)) || + (Options.DisableDevicesIgnoreAfterAnyoneDied.GetBool() && GameStates.AlreadyDied); var admins = Object.FindObjectsOfType(true); var consoles = Object.FindObjectsOfType(true); if (admins == null || consoles == null) return; diff --git a/Modules/EAC.cs b/Modules/EAC.cs index 57df892c4..34164c9bb 100644 --- a/Modules/EAC.cs +++ b/Modules/EAC.cs @@ -1,10 +1,10 @@ -using System; +using AmongUs.GameOptions; +using Hazel; +using InnerNet; +using System; using System.Collections.Generic; using System.IO; using System.Linq; -using AmongUs.GameOptions; -using Hazel; -using InnerNet; using TOHE.Modules; using static TOHE.Translator; diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index 3f0222828..6d9dcc8dc 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -1,13 +1,14 @@ +using AmongUs.GameOptions; +using HarmonyLib; +using Hazel; +using InnerNet; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; -using AmongUs.GameOptions; -using HarmonyLib; -using Hazel; -using InnerNet; using TOHE.Modules; +using TOHE.Patches; using TOHE.Roles.AddOns.Crewmate; using TOHE.Roles.AddOns.Impostor; using TOHE.Roles.Crewmate; @@ -138,7 +139,7 @@ static class ExtendedPlayerControl Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] = name; HudManagerPatch.LastSetNameDesyncCount++; - Logger.Info($"Set:{player?.Data?.PlayerName}:{name} for {seer.GetNameWithRole().RemoveHtmlTags()}", "RpcSetNamePrivate"); + Logger.Info($"Set:{player.Data?.PlayerName}:{name} for {seer.GetNameWithRole().RemoveHtmlTags()}", "RpcSetNamePrivate"); var clientId = seer.GetClientId(); MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(player.NetId, (byte)RpcCalls.SetName, SendOption.Reliable, clientId); @@ -281,10 +282,10 @@ static class ExtendedPlayerControl if (target == null) target = player; if (time >= 0f) Main.AllPlayerKillCooldown[player.PlayerId] = time * 2; else Main.AllPlayerKillCooldown[player.PlayerId] *= 2; - if (player.Is(CustomRoles.Glitch)) + if (player.Is(CustomRoles.Glitch) && Main.PlayerStates[player.PlayerId].Role is Glitch gc) { - Glitch.LastKill = TimeStamp + ((int)(time / 2) - Glitch.KillCooldown.GetInt()); - Glitch.KCDTimer = (int)(time / 2); + gc.LastKill = TimeStamp + ((int)(time / 2) - Glitch.KillCooldown.GetInt()); + gc.KCDTimer = (int)(time / 2); } else if (forceAnime || !player.IsModClient() || !Options.DisableShieldAnimations.GetBool()) { @@ -301,6 +302,7 @@ static class ExtendedPlayerControl writer.Write(time); AmongUsClient.Instance.FinishRpcImmediately(writer); } + Main.AllPlayerControls.Where(x => x.Is(CustomRoles.Observer) && target.PlayerId != x.PlayerId).Do(x => x.RpcGuardAndKill(target, 11, true, fromSetKCD: true)); } if (player.GetCustomRole() is not CustomRoles.Inhibitor and not CustomRoles.Saboteur) player.ResetKillCooldown(); @@ -347,30 +349,30 @@ static class ExtendedPlayerControl } } -/* - [Obsolete] - public static void RpcSpecificProtectPlayer(this PlayerControl killer, PlayerControl target = null, int colorId = 0) - { - if (AmongUsClient.Instance.AmClient) + /* + [Obsolete] + public static void RpcSpecificProtectPlayer(this PlayerControl killer, PlayerControl target = null, int colorId = 0) { - killer.ProtectPlayer(target, colorId); + if (AmongUsClient.Instance.AmClient) + { + killer.ProtectPlayer(target, colorId); + } + MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)RpcCalls.ProtectPlayer, SendOption.Reliable, killer.GetClientId()); + messageWriter.WriteNetObject(target); + messageWriter.Write(colorId); + AmongUsClient.Instance.FinishRpcImmediately(messageWriter); } - MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)RpcCalls.ProtectPlayer, SendOption.Reliable, killer.GetClientId()); - messageWriter.WriteNetObject(target); - messageWriter.Write(colorId); - AmongUsClient.Instance.FinishRpcImmediately(messageWriter); - } -*/ + */ public static void RpcResetAbilityCooldown(this PlayerControl target) { if (!AmongUsClient.Instance.AmHost) return; //ホスト以外が実行しても何も起こさない Logger.Info($"Reset Ability Cooldown for {target.name} (ID: {target.PlayerId})", "RpcResetAbilityCooldown"); - if (target.Is(CustomRoles.Glitch)) + if (target.Is(CustomRoles.Glitch) && Main.PlayerStates[target.PlayerId].Role is Glitch gc) { - Glitch.LastHack = TimeStamp; - Glitch.LastMimic = TimeStamp; - Glitch.MimicCDTimer = 10; - Glitch.HackCDTimer = 10; + gc.LastHack = TimeStamp; + gc.LastMimic = TimeStamp; + gc.MimicCDTimer = 10; + gc.HackCDTimer = 10; } else if (PlayerControl.LocalPlayer == target) { @@ -538,7 +540,12 @@ static class ExtendedPlayerControl } public static bool CanUseKillButton(this PlayerControl pc) { - return pc.IsAlive() && pc.Data.Role.Role != RoleTypes.GuardianAngel && !Pelican.IsEaten(pc.PlayerId) && Options.CurrentGameMode is not (CustomGameMode.MoveAndStop or CustomGameMode.HotPotato) && !Penguin.IsVictim(pc) && (Mastermind.ManipulatedPlayers.ContainsKey(pc.PlayerId) || Main.PlayerStates.TryGetValue(pc.PlayerId, out var state) && state.Role.CanUseKillButton(pc)); + if (!pc.IsAlive()) return false; + if (Mastermind.ManipulatedPlayers.ContainsKey(pc.PlayerId)) return true; + if (Penguin.IsVictim(pc)) return false; + if (Options.CurrentGameMode is CustomGameMode.HotPotato or CustomGameMode.MoveAndStop) return false; + if (Pelican.IsEaten(pc.PlayerId)) return false; + if (pc.Data.Role.Role == RoleTypes.GuardianAngel) return false; return pc.GetCustomRole() switch { @@ -550,120 +557,11 @@ static class ExtendedPlayerControl CustomRoles.Tasker => false, //Hot Potato CustomRoles.Potato => false, - //Standard - CustomRoles.FireWorks => FireWorks.CanUseKillButton(pc), - CustomRoles.Mafia => CanMafiaKill(), - // CustomRoles.Mare => pc.IsAlive(), - //CustomRoles.Underdog => playerCount <= Options.UnderdogMaximumPlayersNeededToKill.GetInt(), - CustomRoles.Underdog => pc.IsAlive(), - CustomRoles.Mastermind => pc.IsAlive(), - CustomRoles.Gambler => pc.IsAlive(), - CustomRoles.RiftMaker => pc.IsAlive(), - CustomRoles.Hitman => pc.IsAlive(), - CustomRoles.Sapper => false, - CustomRoles.Penguin => pc.IsAlive(), - CustomRoles.Stealth => pc.IsAlive(), - CustomRoles.Nullifier => pc.IsAlive(), - CustomRoles.Chronomancer => pc.IsAlive(), - CustomRoles.Mafioso => pc.IsAlive(), - CustomRoles.Consort => pc.IsAlive(), - CustomRoles.Duellist => pc.IsAlive(), - CustomRoles.YinYanger => pc.IsAlive(), - CustomRoles.Librarian => pc.IsAlive() && Librarian.CanUseKillButton(pc), - CustomRoles.Cantankerous => pc.IsAlive() && Cantankerous.CanUseKillButton(pc.PlayerId), - CustomRoles.Swiftclaw => pc.IsAlive(), - CustomRoles.Kidnapper => pc.IsAlive(), - CustomRoles.Swapster => pc.IsAlive(), - CustomRoles.Kamikaze => pc.IsAlive(), - CustomRoles.Inhibitor => !IsActive(SystemTypes.Electrical) && !IsActive(SystemTypes.Comms) && !IsActive(SystemTypes.MushroomMixupSabotage) && !IsActive(SystemTypes.Laboratory) && !IsActive(SystemTypes.LifeSupp) && !IsActive(SystemTypes.Reactor) && !IsActive(SystemTypes.HeliSabotage), - CustomRoles.Saboteur => IsActive(SystemTypes.Electrical) || IsActive(SystemTypes.Comms) || IsActive(SystemTypes.MushroomMixupSabotage) || IsActive(SystemTypes.Laboratory) || IsActive(SystemTypes.LifeSupp) || IsActive(SystemTypes.Reactor) || IsActive(SystemTypes.HeliSabotage), - CustomRoles.Sniper => Sniper.CanUseKillButton(pc), - CustomRoles.Sheriff => Sheriff.CanUseKillButton(pc.PlayerId), - CustomRoles.Crusader => Crusader.CanUseKillButton(pc.PlayerId), - CustomRoles.CopyCat => pc.IsAlive(), - CustomRoles.Jailor => pc.IsAlive(), - CustomRoles.Pelican => pc.IsAlive(), - CustomRoles.SwordsMan => pc.IsAlive() && !SwordsMan.IsKilled(pc.PlayerId), - CustomRoles.Jackal => pc.IsAlive(), - CustomRoles.Sidekick => pc.IsAlive(), - CustomRoles.HexMaster => pc.IsAlive(), - CustomRoles.Bandit => pc.IsAlive(), - CustomRoles.Agitater => pc.IsAlive(), - CustomRoles.Poisoner => pc.IsAlive(), - CustomRoles.Juggernaut => pc.IsAlive(), - //CustomRoles.Reverie => pc.IsAlive(), - CustomRoles.Ritualist => pc.IsAlive(), - CustomRoles.Pyromaniac => pc.IsAlive(), - CustomRoles.Eclipse => pc.IsAlive(), - CustomRoles.NSerialKiller => pc.IsAlive(), - CustomRoles.SoulHunter => pc.IsAlive(), - CustomRoles.Enderman => pc.IsAlive(), - CustomRoles.Mycologist => pc.IsAlive(), - CustomRoles.Bubble => pc.IsAlive(), - CustomRoles.Hookshot => pc.IsAlive(), - CustomRoles.Sprayer => pc.IsAlive(), - CustomRoles.PlagueDoctor => pc.IsAlive() && PlagueDoctor.CanUseKillButton(), - CustomRoles.Postman => pc.IsAlive() && !Postman.IsFinished, - CustomRoles.Magician => pc.IsAlive(), - CustomRoles.WeaponMaster => pc.IsAlive() && WeaponMaster.CanKill(), - CustomRoles.Reckless => pc.IsAlive(), - CustomRoles.Vengeance => pc.IsAlive(), - CustomRoles.HeadHunter => pc.IsAlive(), - CustomRoles.Imitator => pc.IsAlive(), - CustomRoles.Werewolf => Werewolf.IsRampaging(pc.PlayerId) && pc.IsAlive(), - CustomRoles.Medusa => pc.IsAlive(), - CustomRoles.Traitor => pc.IsAlive(), - CustomRoles.Glitch => pc.IsAlive(), - CustomRoles.Pickpocket => pc.IsAlive(), - CustomRoles.Maverick => pc.IsAlive(), - CustomRoles.Jinx => pc.IsAlive(), - CustomRoles.Parasite => pc.IsAlive(), - CustomRoles.Refugee => pc.IsAlive(), - //CustomRoles.NWitch => pc.IsAlive(), - CustomRoles.Wraith => pc.IsAlive(), - CustomRoles.Bomber => Options.BomberCanKill.GetBool() && pc.IsAlive(), - CustomRoles.Nuker => false, - CustomRoles.Innocent => pc.IsAlive(), - //CustomRoles.Counterfeiter => Counterfeiter.CanUseKillButton(pc.PlayerId), - CustomRoles.Aid => pc.IsAlive() && pc.GetAbilityUseLimit() >= 1, - CustomRoles.Escort => pc.IsAlive() && pc.GetAbilityUseLimit() >= 1, - CustomRoles.DonutDelivery => pc.IsAlive() && pc.GetAbilityUseLimit() >= 1, - CustomRoles.Gaulois => pc.IsAlive() && pc.GetAbilityUseLimit() >= 1, - CustomRoles.Analyzer => pc.IsAlive() && Analyzer.CanUseKillButton(pc.PlayerId), - CustomRoles.Witness => pc.IsAlive(), - CustomRoles.Pursuer => Pursuer.CanUseKillButton(pc.PlayerId), - CustomRoles.Morphling => Morphling.CanUseKillButton(pc.PlayerId), - CustomRoles.FFF => pc.IsAlive(), - CustomRoles.Medic => Medic.CanUseKillButton(pc.PlayerId), - CustomRoles.Gamer => pc.IsAlive(), - CustomRoles.DarkHide => DarkHide.CanUseKillButton(pc), - CustomRoles.Assassin => Assassin.CanUseKillButton(pc), - CustomRoles.Undertaker => Undertaker.CanUseKillButton(pc), - CustomRoles.BloodKnight => pc.IsAlive(), - CustomRoles.Doppelganger => pc.IsAlive(), - CustomRoles.Crewpostor => false, - CustomRoles.Totocalcio => Totocalcio.CanUseKillButton(pc), - CustomRoles.Romantic => pc.IsAlive(), - CustomRoles.RuthlessRomantic => pc.IsAlive(), - CustomRoles.VengefulRomantic => VengefulRomantic.CanUseKillButton(pc), - CustomRoles.Succubus => Succubus.CanUseKillButton(pc), - CustomRoles.Necromancer => Necromancer.CanUseKillButton(pc), - CustomRoles.Deathknight => Deathknight.CanUseKillButton(pc), - //CustomRoles.CursedSoul => CursedSoul.CanUseKillButton(pc), - CustomRoles.Amnesiac => Amnesiac.CanUseKillButton(pc), - //CustomRoles.Warlock => !Main.isCurseAndKill.TryGetValue(pc.PlayerId, out bool wcs) || !wcs, - CustomRoles.Monarch => Monarch.CanUseKillButton(pc), - CustomRoles.Deputy => Deputy.CanUseKillButton(pc), - CustomRoles.Virus => pc.IsAlive(), - CustomRoles.Farseer => pc.IsAlive(), - CustomRoles.Spiritcaller => pc.IsAlive(), - CustomRoles.PlagueBearer => pc.IsAlive(), - CustomRoles.Pestilence => pc.IsAlive(), - //CustomRoles.Pirate => pc.IsAlive(), - _ => pc.Is(CustomRoleTypes.Impostor), + _ => Main.PlayerStates.TryGetValue(pc.PlayerId, out var state) && state.Role.CanUseKillButton(pc) }; } + public static bool CanUseImpostorVentButton(this PlayerControl pc) { if (!pc.IsAlive() || pc.Data.Role.Role == RoleTypes.GuardianAngel || Penguin.IsVictim(pc)) return false; @@ -673,73 +571,6 @@ static class ExtendedPlayerControl return pc.GetCustomRole() switch { - CustomRoles.Minimalism or - CustomRoles.Sheriff or - CustomRoles.Deputy or - // CustomRoles.SwordsMan or - CustomRoles.FFF or - CustomRoles.Medic or - // CustomRoles.NWitch or - CustomRoles.Monarch or - CustomRoles.Totocalcio or - CustomRoles.Romantic or - CustomRoles.Succubus or - CustomRoles.Deathknight or - CustomRoles.Necromancer or - CustomRoles.Doppelganger or - //CustomRoles.CursedSoul or - CustomRoles.PlagueBearer or - CustomRoles.Amnesiac or - CustomRoles.PlagueDoctor or - CustomRoles.Crusader - => false, - - CustomRoles.Jackal => Jackal.CanVent.GetBool(), - CustomRoles.VengefulRomantic => Romantic.VengefulCanVent.GetBool(), - CustomRoles.RuthlessRomantic => Romantic.RuthlessCanVent.GetBool(), - CustomRoles.Sidekick => Jackal.CanVentSK.GetBool(), - CustomRoles.Glitch => Glitch.CanVent.GetBool(), - CustomRoles.Poisoner => Poisoner.CanVent.GetBool(), - CustomRoles.SoulHunter => SoulHunter.CanVent.GetBool(), - CustomRoles.Enderman => Enderman.CanVent.GetBool(), - CustomRoles.Mycologist => true, - CustomRoles.Bubble => Bubble.CanVent.GetBool(), - CustomRoles.Hookshot => Hookshot.CanVent.GetBool(), - CustomRoles.Sprayer => Sprayer.CanVent.GetBool(), - CustomRoles.Magician => Magician.CanVent.GetBool(), - CustomRoles.Reckless => Reckless.CanVent.GetBool(), - CustomRoles.WeaponMaster => WeaponMaster.CanVent.GetBool(), - CustomRoles.Postman => Postman.CanVent.GetBool(), - CustomRoles.Pyromaniac => Pyromaniac.CanVent.GetBool(), - CustomRoles.Eclipse => Eclipse.CanVent.GetBool(), - CustomRoles.Vengeance => Vengeance.CanVent.GetBool(), - CustomRoles.HeadHunter => HeadHunter.CanVent.GetBool(), - CustomRoles.Imitator => Imitator.CanVent.GetBool(), - CustomRoles.DarkHide => DarkHide.CanVent.GetBool(), - CustomRoles.Werewolf => Werewolf.CanRampage(pc.PlayerId) || pc.inVent || Werewolf.IsRampaging(pc.PlayerId), - CustomRoles.Pestilence => PlagueBearer.PestilenceCanVent.GetBool(), - CustomRoles.Medusa => Medusa.CanVent.GetBool(), - CustomRoles.Traitor => Traitor.CanVent.GetBool(), - //CustomRoles.NWitch => NWitch.CanVent.GetBool(), - CustomRoles.Maverick => Maverick.CanVent.GetBool(), - CustomRoles.Jinx => Jinx.CanVent.GetBool(), - CustomRoles.Pelican => Pelican.CanVent.GetBool(), - CustomRoles.Gamer => Gamer.CanVent.GetBool(), - CustomRoles.BloodKnight => BloodKnight.CanVent.GetBool(), - CustomRoles.Juggernaut => Juggernaut.CanVent.GetBool(), - CustomRoles.Ritualist => Ritualist.CanVent.GetBool(), - CustomRoles.Virus => Virus.CanVent.GetBool(), - CustomRoles.SwordsMan => SwordsMan.CanVent.GetBool(), - CustomRoles.Pickpocket => Pickpocket.CanVent.GetBool(), - CustomRoles.Bandit => Bandit.CanVent.GetBool(), - CustomRoles.HexMaster => true, - CustomRoles.Wraith => true, - // CustomRoles.Chameleon => true, - CustomRoles.Parasite => true, - CustomRoles.Refugee => true, - CustomRoles.Wildling => Wildling.CanVent.GetBool(), - CustomRoles.Spiritcaller => Spiritcaller.CanVent.GetBool(), - //SoloKombat CustomRoles.KB_Normal => true, //FFA @@ -749,89 +580,14 @@ static class ExtendedPlayerControl //Hot Potato CustomRoles.Potato => false, - _ => pc.Is(CustomRoleTypes.Impostor), + _ => Main.PlayerStates[pc.PlayerId].Role.CanUseImpostorVentButton(pc), }; } public static bool CanUseSabotage(this PlayerControl pc) // NOTE: THIS IS FOR THE HUD FOR MODDED CLIENTS, THIS DOES NOT DETERMINE WHETHER A ROLE CAN SABOTAGE { if (!pc.IsAlive() || pc.Data.Role.Role == RoleTypes.GuardianAngel) return false; - return pc.GetCustomRole() switch - { - CustomRoles.Sheriff or - CustomRoles.Crusader or - CustomRoles.CopyCat or - //CustomRoles.CursedSoul or - CustomRoles.Amnesiac or - CustomRoles.Monarch or - CustomRoles.Deputy or - CustomRoles.Arsonist or - CustomRoles.Medusa or - CustomRoles.SwordsMan or - //CustomRoles.Reverie or - CustomRoles.Innocent or - CustomRoles.Pelican or - //CustomRoles.Counterfeiter or - CustomRoles.Aid or - CustomRoles.DonutDelivery or - CustomRoles.Gaulois or - CustomRoles.Analyzer or - CustomRoles.Escort or - CustomRoles.Pursuer or - CustomRoles.FFF or - CustomRoles.Medic or - CustomRoles.Gamer or - CustomRoles.HexMaster or - CustomRoles.Wraith or - CustomRoles.Juggernaut or - CustomRoles.Jinx or - CustomRoles.DarkHide or - CustomRoles.BloodKnight or - CustomRoles.Poisoner or - CustomRoles.Pyromaniac or - CustomRoles.Eclipse or - CustomRoles.NSerialKiller or - CustomRoles.SoulHunter or - CustomRoles.Bubble or - CustomRoles.PlagueDoctor or - CustomRoles.Reckless or - CustomRoles.Postman or - CustomRoles.Vengeance or - CustomRoles.HeadHunter or - CustomRoles.Imitator or - CustomRoles.Maverick or - //CustomRoles.NWitch or - CustomRoles.Ritualist or - CustomRoles.Totocalcio or - CustomRoles.Succubus or - CustomRoles.Necromancer or - CustomRoles.Deathknight or - CustomRoles.Virus or - CustomRoles.Farseer or - CustomRoles.Pickpocket or - CustomRoles.PlagueBearer or - CustomRoles.Pestilence or - CustomRoles.Romantic or - CustomRoles.VengefulRomantic or - CustomRoles.RuthlessRomantic or - CustomRoles.Werewolf or - CustomRoles.Spiritcaller - => false, - - CustomRoles.Jackal => Jackal.CanUseSabotage.GetBool(), - CustomRoles.Sidekick => Jackal.CanUseSabotageSK.GetBool(), - CustomRoles.Parasite => true, - CustomRoles.Enderman => true, - CustomRoles.Mycologist => Mycologist.SpreadAction.GetValue() == 1, - CustomRoles.Hookshot => true, - CustomRoles.Sprayer => true, - CustomRoles.Glitch => true, - CustomRoles.Refugee => true, - CustomRoles.Magician => true, - CustomRoles.WeaponMaster => true, - - _ => pc.Is(CustomRoleTypes.Impostor), - }; + return Main.PlayerStates[pc.PlayerId].Role.CanUseSabotage(pc); } public static Vector2 Pos(this PlayerControl pc) => new(pc.transform.position.x, pc.transform.position.y); public static void AddKillTimerToDict(this PlayerControl pc, bool half = false, float CD = -1f) @@ -906,326 +662,14 @@ static class ExtendedPlayerControl public static bool IsPlayerShifted(this byte id) => Main.CheckShapeshift.TryGetValue(id, out var shifted) && shifted; public static void ResetKillCooldown(this PlayerControl player) { - Main.AllPlayerKillCooldown[player.PlayerId] = Options.DefaultKillCooldown; //キルクールをデフォルトキルクールに変更 - switch (player.GetCustomRole()) + Main.PlayerStates[player.PlayerId].Role.SetKillCooldown(player.PlayerId); + + Main.AllPlayerKillCooldown[player.PlayerId] = player.GetCustomRole() switch { - case CustomRoles.SerialKiller: - SerialKiller.ApplyKillCooldown(player.PlayerId); //シリアルキラーはシリアルキラーのキルクールに。 - break; - case CustomRoles.TimeThief: - TimeThief.SetKillCooldown(player.PlayerId); //タイムシーフはタイムシーフのキルクールに。 - break; - /* case CustomRoles.Mare: - Mare.SetKillCooldown(player.PlayerId); - break; */ - case CustomRoles.EvilDiviner: - EvilDiviner.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Jailor: - Jailor.SetKillCooldown(player.PlayerId); //シリアルキラーはシリアルキラーのキルクールに。 - break; - case CustomRoles.Morphling: - Morphling.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Cantankerous: - Cantankerous.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Doppelganger: - Doppelganger.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Ritualist: - Ritualist.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Pickpocket: - Pickpocket.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Agitater: - Agitater.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.YinYanger: - YinYanger.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Mafioso: - Mafioso.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Chronomancer: - Chronomancer.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Nullifier: - Nullifier.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Stealth: - Stealth.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Sapper: - Main.AllPlayerKillCooldown[player.PlayerId] = 300f; - break; - case CustomRoles.Hitman: - Main.AllPlayerKillCooldown[player.PlayerId] = Hitman.KillCooldown.GetFloat(); - break; - case CustomRoles.Mastermind: - Main.AllPlayerKillCooldown[player.PlayerId] = Mastermind.KillCooldown.GetFloat(); - break; - case CustomRoles.Gambler: - Main.AllPlayerKillCooldown[player.PlayerId] = Gambler.KillCooldown.GetFloat(); - break; - case CustomRoles.RiftMaker: - Main.AllPlayerKillCooldown[player.PlayerId] = RiftMaker.KillCooldown.GetFloat(); - break; - case CustomRoles.Saboteur: - Main.AllPlayerKillCooldown[player.PlayerId] = Options.SaboteurCDAfterMeetings.GetFloat(); - break; - case CustomRoles.Jackal: - Jackal.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Sidekick: - Sidekick.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.PlagueBearer: - PlagueBearer.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Bandit: - Bandit.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Pestilence: - Pestilence.SetKillCooldownPestilence(player.PlayerId); - break; - case CustomRoles.Councillor: - Councillor.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.HexMaster: - case CustomRoles.Wraith: - Main.AllPlayerKillCooldown[player.PlayerId] = Options.DefaultKillCooldown; - break; - case CustomRoles.NSerialKiller: - NSerialKiller.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.SoulHunter: - SoulHunter.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Enderman: - Enderman.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Mycologist: - Mycologist.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Bubble: - Bubble.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Hookshot: - Hookshot.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Sprayer: - Sprayer.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.PlagueDoctor: - PlagueDoctor.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Penguin: - Penguin.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.WeaponMaster: - WeaponMaster.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Magician: - Magician.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Reckless: - Reckless.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Postman: - Postman.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.HeadHunter: - Main.AllPlayerKillCooldown[player.PlayerId] = HeadHunter.KCD; - break; - case CustomRoles.Pyromaniac: - Pyromaniac.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Eclipse: - Eclipse.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Vengeance: - Vengeance.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Imitator: - Imitator.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Werewolf: - Werewolf.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Traitor: - Traitor.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Glitch: - Glitch.SetKillCooldown(player.PlayerId); - break; - //case CustomRoles.NWitch: - // NWitch.SetKillCooldown(player.PlayerId); - // break; - case CustomRoles.Maverick: - Maverick.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Jinx: - Jinx.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Poisoner: - Poisoner.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Sheriff: - Sheriff.SetKillCooldown(player.PlayerId); //シェリフはシェリフのキルクールに。 - break; - case CustomRoles.CopyCat: - CopyCat.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.SwordsMan: - SwordsMan.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Bomber: - if (Options.BomberCanKill.GetBool()) - Main.AllPlayerKillCooldown[player.PlayerId] = Options.BomberKillCD.GetFloat(); - else - Main.AllPlayerKillCooldown[player.PlayerId] = 300f; - break; - case CustomRoles.Nuker: - Main.AllPlayerKillCooldown[player.PlayerId] = 300f; - break; - case CustomRoles.Pelican: - Main.AllPlayerKillCooldown[player.PlayerId] = Pelican.KillCooldown.GetFloat(); - break; - //case CustomRoles.Counterfeiter: - // Counterfeiter.SetKillCooldown(player.PlayerId); - // break; - case CustomRoles.Aid: - Aid.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Escort: - Escort.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.DonutDelivery: - DonutDelivery.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Gaulois: - Gaulois.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Analyzer: - Analyzer.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Pursuer: - Pursuer.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.FFF: - Main.AllPlayerKillCooldown[player.PlayerId] = 15f; - break; - case CustomRoles.Medusa: - Medusa.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Medic: - Medic.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Gamer: - Gamer.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.BallLightning: - BallLightning.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.DarkHide: - DarkHide.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Greedier: - Greedier.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.QuickShooter: - QuickShooter.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Assassin: - Assassin.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Undertaker: - Undertaker.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Sans: - Sans.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Juggernaut: - Juggernaut.SetKillCooldown(player.PlayerId); - break; - //case CustomRoles.Reverie: - // Reverie.SetKillCooldown(player.PlayerId); - // break; - case CustomRoles.Hacker: - Hacker.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.KB_Normal: - Main.AllPlayerKillCooldown[player.PlayerId] = SoloKombatManager.KB_ATKCooldown.GetFloat(); - break; - case CustomRoles.Killer: - Main.AllPlayerKillCooldown[player.PlayerId] = FFAManager.FFA_KCD.GetFloat(); - break; - case CustomRoles.BloodKnight: - BloodKnight.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Totocalcio: - Totocalcio.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Romantic: - Romantic.SetKillCooldown(); - break; - case CustomRoles.VengefulRomantic: - Main.AllPlayerKillCooldown[player.PlayerId] = Romantic.VengefulKCD.GetFloat(); - break; - case CustomRoles.RuthlessRomantic: - Main.AllPlayerKillCooldown[player.PlayerId] = Romantic.RuthlessKCD.GetFloat(); - break; - case CustomRoles.Gangster: - Gangster.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Succubus: - Succubus.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Deathknight: - Deathknight.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Necromancer: - Necromancer.SetKillCooldown(player.PlayerId); - break; - //case CustomRoles.CursedSoul: - // CursedSoul.SetKillCooldown(player.PlayerId); - // break; - case CustomRoles.Amnesiac: - Amnesiac.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Monarch: - Monarch.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Deputy: - Deputy.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Virus: - Virus.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Farseer: - Farseer.SetCooldown(player.PlayerId); - break; - case CustomRoles.Dazzler: - Dazzler.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Deathpact: - Deathpact.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Devourer: - Devourer.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Spiritcaller: - Spiritcaller.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Lurker: - Lurker.SetKillCooldown(player.PlayerId); - break; - case CustomRoles.Crusader: - Crusader.SetKillCooldown(player.PlayerId); - break; - } + CustomRoles.KB_Normal => SoloKombatManager.KB_ATKCooldown.GetFloat(), + CustomRoles.Killer => FFAManager.FFA_KCD.GetFloat(), + _ => Main.AllPlayerKillCooldown[player.PlayerId] + }; if (player.PlayerId == LastImpostor.currentId) LastImpostor.SetKillCooldown(); if (player.Is(CustomRoles.Mare)) @@ -1325,33 +769,33 @@ static class ExtendedPlayerControl killer.RpcMurderPlayer(target, true); } -/* - public static void RpcMurderPlayerV2(this PlayerControl killer, PlayerControl target) - { - target.RemoveProtection(); - MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(target.NetId, (byte)RpcCalls.MurderPlayer, SendOption.Reliable); - messageWriter.WriteNetObject(target); - messageWriter.Write((int)MurderResultFlags.FailedProtected); - AmongUsClient.Instance.FinishRpcImmediately(messageWriter); - - if (killer.AmOwner) + /* + public static void RpcMurderPlayerV2(this PlayerControl killer, PlayerControl target) { - killer.RpcMurderPlayer(target, true); - } - else - { - killer.MurderPlayer(target, ResultFlags); - MessageWriter messageWriter2 = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)RpcCalls.MurderPlayer, SendOption.Reliable); - messageWriter2.WriteNetObject(target); - messageWriter2.Write((int)ResultFlags); - AmongUsClient.Instance.FinishRpcImmediately(messageWriter2); - } - target.Data.IsDead = true; + target.RemoveProtection(); + MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(target.NetId, (byte)RpcCalls.MurderPlayer, SendOption.Reliable); + messageWriter.WriteNetObject(target); + messageWriter.Write((int)MurderResultFlags.FailedProtected); + AmongUsClient.Instance.FinishRpcImmediately(messageWriter); - NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); - NotifyRoles(SpecifySeer: target); - } -*/ + if (killer.AmOwner) + { + killer.RpcMurderPlayer(target, true); + } + else + { + killer.MurderPlayer(target, ResultFlags); + MessageWriter messageWriter2 = AmongUsClient.Instance.StartRpcImmediately(killer.NetId, (byte)RpcCalls.MurderPlayer, SendOption.Reliable); + messageWriter2.WriteNetObject(target); + messageWriter2.Write((int)ResultFlags); + AmongUsClient.Instance.FinishRpcImmediately(messageWriter2); + } + target.Data.IsDead = true; + + NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); + NotifyRoles(SpecifySeer: target); + } + */ public static bool RpcCheckAndMurder(this PlayerControl killer, PlayerControl target, bool check = false) => CheckMurderPatch.RpcCheckAndMurder(killer, target, check); public static void NoCheckStartMeeting(this PlayerControl reporter, GameData.PlayerInfo target, bool force = false) @@ -1364,7 +808,7 @@ static class ExtendedPlayerControl } public static bool IsModClient(this PlayerControl player) => Main.playerVersion.ContainsKey(player.PlayerId); - public static List GetPlayersInAbilityRangeSorted(this PlayerControl player, bool ignoreColliders = false) => GetPlayersInAbilityRangeSorted(player, pc => true, ignoreColliders); + public static List GetPlayersInAbilityRangeSorted(this PlayerControl player, bool ignoreColliders = false) => GetPlayersInAbilityRangeSorted(player, _ => true, ignoreColliders); public static List GetPlayersInAbilityRangeSorted(this PlayerControl player, Predicate predicate, bool ignoreColliders = false) { @@ -1462,12 +906,12 @@ static class ExtendedPlayerControl if (target == null || target.Is(CustomRoles.GM)) return false; return GameStates.IsLobby || !Main.PlayerStates.TryGetValue(target.PlayerId, out var ps) || !ps.IsDead; } -/* - public static bool IsExiled(this PlayerControl target) - { - return GameStates.InGame || (target != null && (Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Vote)); - } -*/ + /* + public static bool IsExiled(this PlayerControl target) + { + return GameStates.InGame || (target != null && (Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Vote)); + } + */ ///Is the player currently protected public static bool IsProtected(this PlayerControl self) => self.protectedByGuardianId > -1; diff --git a/Modules/GameOptionsSender/GameOptionsSender.cs b/Modules/GameOptionsSender/GameOptionsSender.cs index c287ada96..3d637bcc9 100644 --- a/Modules/GameOptionsSender/GameOptionsSender.cs +++ b/Modules/GameOptionsSender/GameOptionsSender.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; using AmongUs.GameOptions; using Hazel; using Il2CppInterop.Runtime.InteropTypes.Arrays; using InnerNet; +using System; +using System.Collections.Generic; using Array = Il2CppSystem.Array; using Buffer = Il2CppSystem.Buffer; @@ -12,6 +12,7 @@ namespace TOHE.Modules; public abstract class GameOptionsSender { #region Static + public readonly static List AllSenders = new(15) { new NormalGameOptionsSender() }; public static void SendAllGameOptions() @@ -49,6 +50,7 @@ public abstract class GameOptionsSender writer.Recycle(); Logger.Error("オプションのキャストに失敗しました", ToString()); } + writer.EndMessage(); // 配列化&送信 @@ -59,6 +61,7 @@ public abstract class GameOptionsSender SendOptionsArray(byteArray); writer.Recycle(); } + public virtual void SendOptionsArray(Il2CppStructArray optionArray) { for (byte i = 0; i < GameManager.Instance.LogicComponents.Count; i++) @@ -69,6 +72,7 @@ public abstract class GameOptionsSender } } } + protected virtual void SendOptionsArray(Il2CppStructArray optionArray, byte LogicOptionsIndex, int targetClientId) { try @@ -100,6 +104,7 @@ public abstract class GameOptionsSender Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray"); } } + public abstract IGameOptions BuildGameOptions(); public virtual bool AmValid() => true; diff --git a/Modules/GameOptionsSender/NormalGameOptionsSender.cs b/Modules/GameOptionsSender/NormalGameOptionsSender.cs index 5a2b42196..e08388f55 100644 --- a/Modules/GameOptionsSender/NormalGameOptionsSender.cs +++ b/Modules/GameOptionsSender/NormalGameOptionsSender.cs @@ -1,5 +1,5 @@ -using System; using AmongUs.GameOptions; +using System; namespace TOHE.Modules; @@ -7,6 +7,7 @@ public class NormalGameOptionsSender : GameOptionsSender { public override IGameOptions BasedGameOptions => GameOptionsManager.Instance.CurrentGameOptions; + public override bool IsDirty { get @@ -19,6 +20,7 @@ public class NormalGameOptionsSender : GameOptionsSender if (glc.TryCast(out var lo)) _logicOptions = lo; } + return _logicOptions != null && _logicOptions.IsDirty; } catch (Exception ex) @@ -27,11 +29,9 @@ public class NormalGameOptionsSender : GameOptionsSender return _logicOptions != null && _logicOptions.IsDirty; } } - protected set - { - _logicOptions?.ClearDirtyFlag(); - } + protected set { _logicOptions?.ClearDirtyFlag(); } } + private LogicOptions _logicOptions; public override IGameOptions BuildGameOptions() diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs index d2cddfd3f..08e9ff579 100644 --- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs +++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs @@ -1,9 +1,9 @@ -using System; -using System.Linq; using AmongUs.GameOptions; using Hazel; using Il2CppInterop.Runtime.InteropTypes.Arrays; using InnerNet; +using System; +using System.Linq; using TOHE.Roles.Crewmate; using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; @@ -14,6 +14,7 @@ namespace TOHE.Modules; public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender { public static void SetDirty(PlayerControl player) => SetDirty(player.PlayerId); + public static void SetDirty(byte playerId) { foreach (var sender in AllSenders.OfType().Where(sender => sender.player.PlayerId == playerId).ToArray()) @@ -40,7 +41,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender public static void SetDirtyToAllV3() { - foreach (var sender in AllSenders.OfType().Where(sender => !sender.IsDirty && sender.player.IsAlive() && ((Main.GrenadierBlinding.Count > 0 && (sender.player.GetCustomRole().IsImpostor() || (sender.player.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()))) || (Grenadier.MadGrenadierBlinding.Count > 0 && !sender.player.GetCustomRole().IsImpostorTeam() && !sender.player.Is(CustomRoles.Madmate)))).ToArray()) + foreach (var sender in AllSenders.OfType().Where(sender => !sender.IsDirty && sender.player.IsAlive() && ((Grenadier.GrenadierBlinding.Count > 0 && (sender.player.GetCustomRole().IsImpostor() || (sender.player.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()))) || (Grenadier.MadGrenadierBlinding.Count > 0 && !sender.player.GetCustomRole().IsImpostorTeam() && !sender.player.Is(CustomRoles.Madmate)))).ToArray()) { sender.SetDirty(); } @@ -56,6 +57,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender public override IGameOptions BasedGameOptions => Main.RealOptionsData.Restore(new NormalGameOptionsV07(new UnityLogger().Cast()).Cast()); + public override bool IsDirty { get; protected set; } public PlayerControl player = player; @@ -72,6 +74,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender if (com.TryCast(out var lo)) lo.SetGameOptions(opt); } + GameOptionsManager.Instance.CurrentGameOptions = opt; } else base.SendGameOptions(); @@ -94,14 +97,16 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender Logger.Fatal(ex.ToString(), "PlayerGameOptionsSender.SendOptionsArray"); } } + public static void RemoveSender(PlayerControl player) { var sender = AllSenders.OfType() - .FirstOrDefault(sender => sender.player.PlayerId == player.PlayerId); + .FirstOrDefault(sender => sender.player.PlayerId == player.PlayerId); if (sender == null) return; sender.player = null; AllSenders.Remove(sender); } + public override IGameOptions BuildGameOptions() { try @@ -130,6 +135,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender opt.SetFloat(FloatOptionNames.CrewLightMod, 1.25f); opt.SetFloat(FloatOptionNames.ImpostorLightMod, 1.25f); } + break; case CustomGameMode.HotPotato: case CustomGameMode.MoveAndStop: @@ -572,7 +578,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender } if ( - (Main.GrenadierBlinding.Count > 0 && + (Grenadier.GrenadierBlinding.Count > 0 && (player.GetCustomRole().IsImpostor() || (player.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool())) ) || ( @@ -588,7 +594,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender switch (player.GetCustomRole()) { - case CustomRoles.Alchemist when Alchemist.VisionPotionActive: + case CustomRoles.Alchemist when (Main.PlayerStates[player.PlayerId].Role as Alchemist).VisionPotionActive: opt.SetVisionV2(); if (Utils.IsActive(SystemTypes.Electrical)) opt.SetFloat(FloatOptionNames.CrewLightMod, Alchemist.VisionOnLightsOut.GetFloat() * 5); else opt.SetFloat(FloatOptionNames.CrewLightMod, Alchemist.Vision.GetFloat()); @@ -615,7 +621,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender opt.SetFloat(FloatOptionNames.ImpostorLightMod, Beacon.IncreasedVision); } - /* if ((Main.FlashbangInProtect.Count > 0 && Main.ForFlashbang.Contains(player.PlayerId) && (!player.GetCustomRole().IsCrewmate()))) + /* if ((Main.FlashbangInProtect.Count > 0 && Main.ForFlashbang.Contains(player.PlayerId) && (!player.GetCustomRole().IsCrewmate()))) { opt.SetVision(false); opt.SetFloat(FloatOptionNames.CrewLightMod, Options.FlashbangVision.GetFloat()); @@ -724,10 +730,12 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender Int32OptionNames.EmergencyCooldown, Options.AdditionalEmergencyCooldownTime.GetInt()); } + if (Options.SyncButtonMode.GetBool() && Options.SyncedButtonCount.GetValue() <= Options.UsedButtonCount) { opt.SetInt(Int32OptionNames.EmergencyCooldown, 3600); } + MeetingTimeManager.ApplyGameOptions(opt); AURoleOptions.ShapeshifterCooldown = Mathf.Max(1f, AURoleOptions.ShapeshifterCooldown); diff --git a/Modules/GameState.cs b/Modules/GameState.cs index 46af5f3c7..e8ed084f6 100644 --- a/Modules/GameState.cs +++ b/Modules/GameState.cs @@ -54,9 +54,24 @@ public class PlayerState(byte playerId) CustomRoles.Arsonist => Options.ArsonistKeepsGameGoing.GetBool() ? CountTypes.Arsonist : CountTypes.Crew, _ => role.GetCountTypes(), }; + Role = role.GetRoleClass(); Role.Init(); Role.Add(PlayerId); + + if (!Main.HasJustStarted) + { + var pc = Utils.GetPlayerById(PlayerId); + pc.ResetKillCooldown(); + pc.SyncSettings(); + Utils.NotifyRoles(SpecifySeer: pc); + Utils.NotifyRoles(SpecifyTarget: pc); + if (PlayerId == PlayerControl.LocalPlayer.PlayerId && GameStates.IsInTask) + { + HudManager.Instance.SetHudActive(true); + RemoveDisableDevicesPatch.UpdateDisableDevices(); + } + } } public void SetSubRole(CustomRoles role, bool AllReplace = false) { @@ -192,7 +207,6 @@ public class PlayerState(byte playerId) Suicide, Spell, Curse, - Hex, FollowingSuicide, Bite, Poison, @@ -217,7 +231,6 @@ public class PlayerState(byte playerId) LossOfHead, Trialed, Infected, - Jinx, Demolished, YinYanged, Kamikazed, @@ -284,8 +297,9 @@ public class TaskState switch (player.GetCustomRole()) { case CustomRoles.SabotageMaster: - SabotageMaster.UsedSkillCount -= SabotageMaster.SMAbilityUseGainWithEachTaskCompleted.GetFloat(); - SabotageMaster.SendRPC(SabotageMaster.UsedSkillCount); + if (Main.PlayerStates[player.PlayerId].Role is not SabotageMaster sm) break; + sm.UsedSkillCount -= SabotageMaster.SMAbilityUseGainWithEachTaskCompleted.GetFloat(); + sm.SendRPC(); break; case CustomRoles.NiceHacker: if (!player.IsModClient() && NiceHacker.UseLimit.ContainsKey(player.PlayerId)) NiceHacker.UseLimit[player.PlayerId] += NiceHacker.NiceHackerAbilityUseGainWithEachTaskCompleted.GetFloat(); @@ -324,46 +338,10 @@ public class TaskState _ => float.MaxValue, }; if (Math.Abs(add - float.MaxValue) > 0.5f && add > 0) player.RpcIncreaseAbilityUseLimitBy(add); - - switch (player.GetCustomRole()) - { - case CustomRoles.Express: - Express.OnTaskComplete(player); - break; - case CustomRoles.Alchemist: - Alchemist.OnTaskComplete(player); - break; - case CustomRoles.Transmitter: - Transmitter.OnTaskComplete(player); - break; - case CustomRoles.Autocrat: - Autocrat.OnTaskComplete(player); - break; - case CustomRoles.Speedrunner: - Speedrunner.OnTaskComplete(player, CompletedTasksCount, AllTasksCount); - break; - case CustomRoles.Electric: - Electric.OnTaskComplete(player); - break; - case CustomRoles.Insight: - Insight.OnTaskComplete(player); - break; - case CustomRoles.Ignitor: - Ignitor.OnCompleteTask(player); - if ((CompletedTasksCount + 1) >= AllTasksCount) Ignitor.OnTasksFinished(player); - break; - case CustomRoles.Merchant: - Merchant.OnTaskFinished(player); - break; - case CustomRoles.Crewpostor: - Crewpostor.OnTaskComplete(player); - break; - case CustomRoles.Rabbit: - Rabbit.OnTaskComplete(player); - break; - } } + Main.PlayerStates[player.PlayerId].Role.OnTaskComplete(player, CompletedTasksCount, AllTasksCount); + var addons = Main.PlayerStates[player.PlayerId].SubRoles; if (addons.Contains(CustomRoles.Stressed)) diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index 9e14a0ec5..422dd5e8b 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -1,10 +1,10 @@ -using System; +using HarmonyLib; +using Hazel; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -using HarmonyLib; -using Hazel; using TMPro; using TOHE.Modules; using TOHE.Roles.AddOns.Common; diff --git a/Modules/LoadingScreen.cs b/Modules/LoadingScreen.cs index 595f5949d..fa67faf26 100644 --- a/Modules/LoadingScreen.cs +++ b/Modules/LoadingScreen.cs @@ -1,5 +1,6 @@ -using System; -using Rewired.Utils; +using Rewired.Utils; +using System; +using TOHE.Patches; using UnityEngine; using Object = UnityEngine.Object; @@ -72,4 +73,4 @@ namespace TOHE.Modules } } } -} +} \ No newline at end of file diff --git a/Modules/MafiaRevengeManager.cs b/Modules/MafiaRevengeManager.cs index 7125e0756..7fc0d5c6c 100644 --- a/Modules/MafiaRevengeManager.cs +++ b/Modules/MafiaRevengeManager.cs @@ -1,14 +1,5 @@ -using System; -using System.Linq; -using HarmonyLib; -using Hazel; -using TOHE.Modules; -using UnityEngine; -using static TOHE.Translator; -using Object = UnityEngine.Object; - -namespace TOHE; +namespace TOHE; public static class MafiaRevengeManager { -} +} \ No newline at end of file diff --git a/Modules/MeetingTimeManager.cs b/Modules/MeetingTimeManager.cs index 900f329b5..071276487 100644 --- a/Modules/MeetingTimeManager.cs +++ b/Modules/MeetingTimeManager.cs @@ -1,5 +1,5 @@ -using System; using AmongUs.GameOptions; +using System; using TOHE.Roles.Crewmate; using TOHE.Roles.Impostor; @@ -19,16 +19,19 @@ public class MeetingTimeManager Logger.Info($"DefaultDiscussionTime: {DefaultDiscussionTime}s, DefaultVotingTime: {DefaultVotingTime}s", "MeetingTimeManager.Init"); ResetMeetingTime(); } + public static void ApplyGameOptions(IGameOptions opt) { opt.SetInt(Int32OptionNames.DiscussionTime, DiscussionTime); opt.SetInt(Int32OptionNames.VotingTime, VotingTime); } + private static void ResetMeetingTime() { DiscussionTime = DefaultDiscussionTime; VotingTime = DefaultVotingTime; } + public static void OnReportDeadBody() { if (Options.AllAliveMeeting.GetBool() && Utils.IsAllAlive) @@ -50,6 +53,7 @@ public class MeetingTimeManager MeetingTimeMinTimeThief = TimeThief.LowerLimitVotingTime.GetInt(); BonusMeetingTime += TimeThief.TotalDecreasedMeetingTime(); } + if (TimeManager.IsEnable) { MeetingTimeMinTimeManager = TimeManager.MadMinMeetingTimeLimit.GetInt(); @@ -74,6 +78,7 @@ public class MeetingTimeManager DiscussionTime = 0; } } + Logger.Info($"Discussion Time: {DiscussionTime}s, Voting Time: {VotingTime}s", "MeetingTimeManager.OnReportDeadBody"); } } \ No newline at end of file diff --git a/Modules/ModUpdater.cs b/Modules/ModUpdater.cs index 9177cd47a..9f030dfdd 100644 --- a/Modules/ModUpdater.cs +++ b/Modules/ModUpdater.cs @@ -1,11 +1,11 @@ -using System; +using HarmonyLib; +using Newtonsoft.Json.Linq; +using System; using System.IO; using System.IO.Compression; using System.Net.Http; using System.Reflection; using System.Threading.Tasks; -using HarmonyLib; -using Newtonsoft.Json.Linq; using Twitch; using UnityEngine; using static TOHE.Translator; @@ -63,8 +63,10 @@ public class ModUpdater { stream.Close(); } + return result; } + public static async Task CheckReleaseFromGithub(bool beta = false) { Logger.Warn("Checking GitHub Release", "CheckRelease"); @@ -81,8 +83,10 @@ public class ModUpdater Logger.Error($"Response Status Code: {response.StatusCode}", "CheckRelease"); return false; } + result = await response.Content.ReadAsStringAsync(); } + JObject data = JObject.Parse(result); if (beta) { @@ -104,6 +108,7 @@ public class ModUpdater break; } } + hasUpdate = latestVersion.CompareTo(Main.version) > 0; hasOutdate = latestVersion.CompareTo(Main.version) < 0; } @@ -120,6 +125,7 @@ public class ModUpdater Logger.Error("No Download URL", "CheckRelease"); return false; } + isChecked = true; isBroken = false; } @@ -129,8 +135,10 @@ public class ModUpdater Logger.Error($"Error while checking release from GitHub:\n{ex}", "CheckRelease", false); return false; } + return true; } + public static void StartUpdate(string url, bool github) { ShowPopup(GetString("updatePleaseWait"), StringNames.Cancel, true, false); @@ -161,8 +169,10 @@ public class ModUpdater Logger.Exception(ex, "NewVersionCheck"); return false; } + return true; } + public static void DeleteOldFiles() { string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); @@ -184,7 +194,9 @@ public class ModUpdater Logger.Error($"Failed to clear update residue\n{e}", "DeleteOldFiles"); } } + private static readonly object downloadLock = new(); + public static async Task DownloadDLL(string url) { try @@ -245,8 +257,10 @@ public class ModUpdater ShowPopup(GetString("updateManually"), StringNames.Close, true); return false; } + return true; } + public static async Task DownloadDLLGithub(string url) { try @@ -297,9 +311,14 @@ public class ModUpdater ShowPopup(GetString("updateManually"), StringNames.Close, true); return false; } + return true; } - private static void DownloadCallBack(long total, long downloaded, double progress) { } + + private static void DownloadCallBack(long total, long downloaded, double progress) + { + } + private static void ShowPopup(string message, StringNames buttonText, bool showButton = false, bool buttonIsExit = true) { if (InfoPopup == null) return; diff --git a/Modules/NameColorManager.cs b/Modules/NameColorManager.cs index ff591bb66..22979bfd7 100644 --- a/Modules/NameColorManager.cs +++ b/Modules/NameColorManager.cs @@ -16,6 +16,7 @@ public static class NameColorManager if (KnowTargetRoleColor(seer, target, isMeeting, out var color)) colorCode = color == "" ? target.GetRoleColorCode() : color; } + string openTag = "", closeTag = ""; if (colorCode != "") { @@ -24,8 +25,10 @@ public static class NameColorManager openTag = $"<{colorCode}>"; closeTag = ""; } + return openTag + name + closeTag; } + private static bool KnowTargetRoleColor(PlayerControl seer, PlayerControl target, bool isMeeting, out string color) { color = ""; @@ -61,6 +64,7 @@ public static class NameColorManager if (target.Is(CustomRoles.Necromancer)) color = Main.roleColors[CustomRoles.Necromancer]; if (target.Is(CustomRoles.Deathknight)) color = Main.roleColors[CustomRoles.Deathknight]; } + if (seer.Is(CustomRoles.Deathknight) && target.Is(CustomRoles.Undead)) color = Main.roleColors[CustomRoles.Undead]; if (seer.Is(CustomRoles.Necromancer) && target.Is(CustomRoles.Undead)) color = Main.roleColors[CustomRoles.Undead]; if ((seer.GetCustomRole() is CustomRoles.Necromancer or CustomRoles.Deathknight) && Necromancer.PartiallyRecruitedIds.Contains(target.PlayerId)) color = Main.roleColors[CustomRoles.Deathknight]; @@ -239,6 +243,7 @@ public static class NameColorManager || EvilDiviner.IsShowTargetRole(seer, target) || Ritualist.IsShowTargetRole(seer, target); } + public static bool TryGetData(PlayerControl seer, PlayerControl target, out string colorCode) { colorCode = ""; @@ -263,6 +268,7 @@ public static class NameColorManager SendRPC(seerId, targetId, colorCode); } + public static void Remove(byte seerId, byte targetId) { var state = Main.PlayerStates[seerId]; @@ -271,12 +277,14 @@ public static class NameColorManager SendRPC(seerId, targetId); } + public static void RemoveAll(byte seerId) { Main.PlayerStates[seerId].TargetColorData.Clear(); SendRPC(seerId); } + private static void SendRPC(byte seerId, byte targetId = byte.MaxValue, string colorCode = "") { if (!AmongUsClient.Instance.AmHost) return; @@ -287,6 +295,7 @@ public static class NameColorManager writer.Write(colorCode); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte seerId = reader.ReadByte(); diff --git a/Modules/NameNotifyManager.cs b/Modules/NameNotifyManager.cs index 790d0f037..b8f5dd6f1 100644 --- a/Modules/NameNotifyManager.cs +++ b/Modules/NameNotifyManager.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using UnityEngine; namespace TOHE; @@ -22,6 +22,7 @@ public static class NameNotifyManager Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc); if (log) Logger.Info($"New name notify for {pc.GetNameWithRole().RemoveHtmlTags()}: {text} ({time}s)", "Name Notify"); } + public static void OnFixedUpdate(PlayerControl player) { if (!GameStates.IsInTask) @@ -29,12 +30,14 @@ public static class NameNotifyManager if (Notice.Count > 0) Notice = []; return; } + if (Notice.ContainsKey(player.PlayerId) && Notice[player.PlayerId].TIMESTAMP < Utils.TimeStamp) { Notice.Remove(player.PlayerId); Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player); } } + public static bool GetNameNotify(PlayerControl player, out string name) { name = string.Empty; @@ -42,6 +45,7 @@ public static class NameNotifyManager name = Notice[player.PlayerId].TEXT; return true; } + private static void SendRPC(byte playerId) { if (!AmongUsClient.Instance.AmHost) return; @@ -54,8 +58,10 @@ public static class NameNotifyManager writer.Write(Notice[playerId].TIMESTAMP - Utils.TimeStamp); } else writer.Write(false); + AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte PlayerId = reader.ReadByte(); diff --git a/Modules/OptionBackup/OptionBackupData.cs b/Modules/OptionBackup/OptionBackupData.cs index 2555eb729..0acfbb6b2 100644 --- a/Modules/OptionBackup/OptionBackupData.cs +++ b/Modules/OptionBackup/OptionBackupData.cs @@ -1,8 +1,8 @@ +using AmongUs.GameOptions; using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using AmongUs.GameOptions; namespace TOHE; diff --git a/Modules/OptionBackup/OptionBackupValue.cs b/Modules/OptionBackup/OptionBackupValue.cs index 7e8cf97e2..d24b0a1cf 100644 --- a/Modules/OptionBackup/OptionBackupValue.cs +++ b/Modules/OptionBackup/OptionBackupValue.cs @@ -1,5 +1,5 @@ -using System; using AmongUs.GameOptions; +using System; namespace TOHE; @@ -9,7 +9,7 @@ public abstract class OptionBackupValue } public abstract class OptionBackupValueBase(NameT name, ValueT value) : OptionBackupValue -where NameT : Enum + where NameT : Enum { public readonly NameT OptionName = name; public readonly ValueT Value = value; @@ -22,6 +22,7 @@ public class ByteOptionBackupValue(ByteOptionNames name, byte value) : OptionBac option.SetByte(OptionName, Value); } } + public class BoolOptionBackupValue(BoolOptionNames name, bool value) : OptionBackupValueBase(name, value) { public override void Restore(IGameOptions option) @@ -30,6 +31,7 @@ public class BoolOptionBackupValue(BoolOptionNames name, bool value) : OptionBac option.SetBool(OptionName, Value); } } + public class FloatOptionBackupValue(FloatOptionNames name, float value) : OptionBackupValueBase(name, value) { public override void Restore(IGameOptions option) @@ -37,6 +39,7 @@ public class FloatOptionBackupValue(FloatOptionNames name, float value) : Option option.SetFloat(OptionName, Value); } } + public class IntOptionBackupValue(Int32OptionNames name, int value) : OptionBackupValueBase(name, value) { public override void Restore(IGameOptions option) @@ -44,6 +47,7 @@ public class IntOptionBackupValue(Int32OptionNames name, int value) : OptionBack option.SetInt(OptionName, Value); } } + public class UIntOptionBackupValue(UInt32OptionNames name, uint value) : OptionBackupValueBase(name, value) { public override void Restore(IGameOptions option) diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index fbe6d7d31..dcf67132c 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -1,8 +1,8 @@ +using HarmonyLib; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using HarmonyLib; using TOHE.Modules; using TOHE.Roles.AddOns.Crewmate; using TOHE.Roles.AddOns.Impostor; diff --git a/Modules/RPC.cs b/Modules/RPC.cs index 0f4d1a1ab..4a5e4e58b 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -1005,8 +1005,6 @@ internal static class RPC Main.PlayerStates[targetId].SetSubRole(role); } - Utils.AddRoles(targetId, role); - HudManager.Instance.SetHudActive(true); if (PlayerControl.LocalPlayer.PlayerId == targetId) RemoveDisableDevicesPatch.UpdateDisableDevices(); } diff --git a/Modules/ServerAddManager.cs b/Modules/ServerAddManager.cs index ffb48bde2..b45c912a6 100644 --- a/Modules/ServerAddManager.cs +++ b/Modules/ServerAddManager.cs @@ -1,16 +1,17 @@ -using System; +using HarmonyLib; +using Il2CppInterop.Runtime.InteropTypes; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Linq.Expressions; -using HarmonyLib; -using Il2CppInterop.Runtime.InteropTypes; namespace TOHE; public static class ServerAddManager { private static readonly ServerManager serverManager = DestroyableSingleton.Instance; + public static void Init() { if (CultureInfo.CurrentCulture.Name.StartsWith("zh") && serverManager.AvailableRegions.Count == 10) return; @@ -40,6 +41,7 @@ public static class ServerAddManager private static class CastHelper where T : Il2CppObjectBase { public static Func Cast; + static CastHelper() { var constructor = typeof(T).GetConstructor([typeof(IntPtr)]); @@ -55,5 +57,4 @@ public static class ServerAddManager if (obj is T casted) return casted; return CastHelper.Cast(obj.Pointer); } - -} +} \ No newline at end of file diff --git a/Modules/TemplateManager.cs b/Modules/TemplateManager.cs index 4c8868f15..20f6c322f 100644 --- a/Modules/TemplateManager.cs +++ b/Modules/TemplateManager.cs @@ -1,3 +1,6 @@ +using AmongUs.Data; +using HarmonyLib; +using InnerNet; using System; using System.Collections.Generic; using System.Globalization; @@ -6,9 +9,6 @@ using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; -using AmongUs.Data; -using HarmonyLib; -using InnerNet; using UnityEngine; using static TOHE.Translator; diff --git a/Modules/Translator.cs b/Modules/Translator.cs index fef96d1c8..fd74110f9 100644 --- a/Modules/Translator.cs +++ b/Modules/Translator.cs @@ -1,3 +1,5 @@ +using HarmonyLib; +using Il2CppInterop.Runtime.InteropTypes.Arrays; using System; using System.Collections.Generic; using System.Globalization; @@ -7,8 +9,6 @@ using System.Reflection; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; -using HarmonyLib; -using Il2CppInterop.Runtime.InteropTypes.Arrays; using Object = Il2CppSystem.Object; namespace TOHE; diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 607c73acf..7318bf0ad 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -1,5 +1,9 @@ +using AmongUs.Data; +using AmongUs.GameOptions; +using Hazel; +using Il2CppInterop.Runtime.InteropTypes; +using InnerNet; using System; -using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -8,12 +12,8 @@ using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using AmongUs.Data; -using AmongUs.GameOptions; -using Hazel; -using Il2CppInterop.Runtime.InteropTypes; -using InnerNet; using TOHE.Modules; +using TOHE.Patches; using TOHE.Roles.AddOns.Common; using TOHE.Roles.AddOns.Crewmate; using TOHE.Roles.AddOns.Impostor; @@ -121,7 +121,7 @@ public static class Utils Logger.Info($"{nt.myPlayer.GetNameWithRole().RemoveHtmlTags()} => {vent.transform.position} (vent)", "TP"); - return TP(nt, new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f), log); + return TP(nt, new(vent.transform.position.x, vent.transform.position.y + 0.3636f), log); } public static ClientData GetClientById(int id) @@ -147,42 +147,49 @@ public static class Utils { if (mapId == 5) return false; // if The Fungle return false var SwitchSystem = ShipStatus.Instance.Systems[type].Cast(); - return SwitchSystem != null && SwitchSystem.IsActive; + return SwitchSystem is { IsActive: true }; } case SystemTypes.Reactor: { - if (mapId == 2) return false; // if Polus return false - if (mapId is 4) // Only Airhip + switch (mapId) { - var HeliSabotageSystem = ShipStatus.Instance.Systems[type].Cast(); - return HeliSabotageSystem != null && HeliSabotageSystem.IsActive; + case 2: + return false; // if Polus return false + // Only Airhip + case 4: + { + var HeliSabotageSystem = ShipStatus.Instance.Systems[type].Cast(); + return HeliSabotageSystem != null && HeliSabotageSystem.IsActive; + } + default: + { + var ReactorSystemType = ShipStatus.Instance.Systems[type].Cast(); + return ReactorSystemType is { IsActive: true }; + } } - - var ReactorSystemType = ShipStatus.Instance.Systems[type].Cast(); - return ReactorSystemType != null && ReactorSystemType.IsActive; } case SystemTypes.Laboratory: { if (mapId != 2) return false; // Only Polus var ReactorSystemType = ShipStatus.Instance.Systems[type].Cast(); - return ReactorSystemType != null && ReactorSystemType.IsActive; + return ReactorSystemType is { IsActive: true }; } case SystemTypes.LifeSupp: { if (mapId is 2 or 4 or 5) return false; // Only Skeld & Mira HQ var LifeSuppSystemType = ShipStatus.Instance.Systems[type].Cast(); - return LifeSuppSystemType != null && LifeSuppSystemType.IsActive; + return LifeSuppSystemType is { IsActive: true }; } case SystemTypes.Comms: { if (mapId is 1 or 5) // Only Mira HQ & The Fungle { var HqHudSystemType = ShipStatus.Instance.Systems[type].Cast(); - return HqHudSystemType != null && HqHudSystemType.IsActive; + return HqHudSystemType is { IsActive: true }; } var HudOverrideSystemType = ShipStatus.Instance.Systems[type].Cast(); - return HudOverrideSystemType != null && HudOverrideSystemType.IsActive; + return HudOverrideSystemType is { IsActive: true }; } case SystemTypes.HeliSabotage: { @@ -291,14 +298,12 @@ public static class Utils { if (seer.Is(CustomRoles.GM) || seer.Is(CustomRoles.Seer)) return true; if (seer.Data.IsDead || killer == seer || target == seer) return false; - if (seer.Is(CustomRoles.EvilTracker)) return EvilTracker.KillFlashCheck(killer, target); - return false; + return seer.Is(CustomRoles.EvilTracker) && EvilTracker.KillFlashCheck(killer, target); } public static void KillFlash(this PlayerControl player) { //Kill flash (blackout + reactor flash) processing - bool ReactorCheck = false; //Checking whether the reactor sabotage is active var systemtypes = (MapNames)Main.NormalOptions.MapId switch { @@ -306,7 +311,7 @@ public static class Utils MapNames.Airship => SystemTypes.HeliSabotage, _ => SystemTypes.Reactor, }; - ReactorCheck = IsActive(systemtypes); + bool ReactorCheck = IsActive(systemtypes); //Checking whether the reactor sabotage is active var Duration = Options.KillFlashDuration.GetFloat(); if (ReactorCheck) Duration += 0.2f; // Extend blackout during reactor @@ -330,7 +335,7 @@ public static class Utils { Main.PlayerStates[player.PlayerId].IsBlackOut = false; // Cancel blackout player.MarkDirtySettings(); - }, Options.KillFlashDuration.GetFloat(), "RemoveKillFlash"); + }, Duration, "RemoveKillFlash"); } public static void BlackOut(this IGameOptions opt, bool IsBlackOut) @@ -389,9 +394,6 @@ public static class Utils public static (string, Color) GetRoleText(byte seerId, byte targetId, bool pure = false) { - string RoleText = "Invalid Role"; - Color RoleColor; - var seerMainRole = Main.PlayerStates[seerId].MainRole; var seerSubRoles = Main.PlayerStates[seerId].SubRoles; @@ -400,8 +402,8 @@ public static class Utils var self = seerId == targetId || Main.PlayerStates[seerId].IsDead; - RoleText = GetRoleName(targetMainRole); - RoleColor = GetRoleColor(targetMainRole); + string RoleText = GetRoleName(targetMainRole); + Color RoleColor = GetRoleColor(targetMainRole); if (LastImpostor.currentId == targetId) RoleText = GetRoleString("Last-") + RoleText; @@ -743,7 +745,6 @@ public static class Utils if (Romantic.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; if (Lawyer.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; if (EvilDiviner.IsShowTargetRole(PlayerControl.LocalPlayer, __instance)) result = true; - if (Ritualist.IsShowTargetRole(PlayerControl.LocalPlayer, __instance)) result = true; if (Executioner.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; if (Succubus.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; if (Necromancer.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; @@ -756,7 +757,6 @@ public static class Utils if (Totocalcio.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; if (Lawyer.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; if (EvilDiviner.IsShowTargetRole(PlayerControl.LocalPlayer, __instance)) result = true; - if (Ritualist.IsShowTargetRole(PlayerControl.LocalPlayer, __instance)) result = true; if (Executioner.KnowRole(PlayerControl.LocalPlayer, __instance)) result = true; if (Main.GodMode.Value) result = true; @@ -792,247 +792,10 @@ public static class Utils if (!Main.playerVersion.ContainsKey(0)) return string.Empty; //ホストがMODを入れていなければ未記入を返す if (Options.CurrentGameMode == CustomGameMode.MoveAndStop) return GetTaskCount(playerId, comms, moveAndStop: true); var ProgressText = new StringBuilder(); - var role = Main.PlayerStates[playerId].MainRole; PlayerControl pc = GetPlayerById(playerId); try { - switch (role) - { - case CustomRoles.Sheriff: - if (Sheriff.ShowShotLimit.GetBool()) ProgressText.Append(Sheriff.GetShotLimit(playerId)); - break; - case CustomRoles.Perceiver: - ProgressText.Append(Perceiver.GetProgressText(playerId)); - break; - case CustomRoles.Convener: - ProgressText.Append(Convener.GetProgressText(playerId)); - break; - case CustomRoles.Kamikaze: - ProgressText.Append(Kamikaze.GetProgressText(playerId)); - break; - case CustomRoles.Analyzer: - ProgressText.Append(Analyzer.GetProgressText()); - break; - case CustomRoles.SoulHunter: - ProgressText.Append(SoulHunter.ProgressText); - break; - case CustomRoles.Sprayer: - ProgressText.Append(Sprayer.ProgressText); - break; - case CustomRoles.Alchemist: - ProgressText.Append(Alchemist.GetProgressText(playerId)); - break; - case CustomRoles.Bandit: - ProgressText.Append(Bandit.GetStealLimit(playerId)); - break; - case CustomRoles.Cleanser: - ProgressText.Append(Cleanser.GetProgressText(playerId)); - break; - case CustomRoles.Doppelganger: - ProgressText.Append(Doppelganger.GetStealLimit(playerId)); - break; - case CustomRoles.SerialKiller: - if (SerialKiller.SuicideTimer.TryGetValue(playerId, out float value)) - { - int SKTime = SerialKiller.TimeLimit.GetInt() - (int)value; - Color SKColor = SKTime < 10 ? SKTime % 2 == 1 ? Color.yellow : Color.red : Color.white; - if (SKTime <= 20) ProgressText.Append(ColorString(SKColor, $"- {SKTime}s")); - } - - break; - case CustomRoles.PlagueDoctor: - ProgressText.Append(PlagueDoctor.GetProgressText()); - break; - case CustomRoles.BountyHunter: - if (BountyHunter.ChangeTimer.TryGetValue(playerId, out float value1)) - { - int BHTime = (int)(BountyHunter.TargetChangeTime - value1); - if (BHTime <= 15) ProgressText.Append(ColorString(Color.white, $"- SWAP: {BHTime}s")); - } - - break; - case CustomRoles.WeaponMaster: - if (!pc.IsModClient()) ProgressText.Append(WeaponMaster.GetHudAndProgressText()); - break; - case CustomRoles.Jailor: - ProgressText.Append(Jailor.GetProgressText(playerId)); - break; - case CustomRoles.NiceSwapper: - ProgressText.Append(GetTaskCount(playerId, comms)); - ProgressText.Append(NiceSwapper.ProgressText); - break; - case CustomRoles.SabotageMaster: - Color TextColor101; - if (SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount < 1) TextColor101 = Color.red; - else TextColor101 = Color.white; - ProgressText.Append(GetTaskCount(playerId, comms)); - ProgressText.Append(ColorString(TextColor101, $" - {Math.Round(SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount, 1)}")); - break; - case CustomRoles.Chameleon: - ProgressText.Append(GetTaskCount(playerId, comms)); - ProgressText.Append(GetAbilityUseLimitDisplay(playerId, Chameleon.IsInvis(playerId))); - break; - case CustomRoles.Crusader: - ProgressText.Append(Crusader.GetSkillLimit(playerId)); - break; - case CustomRoles.Benefactor: - ProgressText.Append(Benefactor.GetProgressText(playerId)); - break; - case CustomRoles.Philantropist: - //ProgressText.Append(Philantropist.GetProgressText(playerId)); - break; - case CustomRoles.CameraMan: - ProgressText.Append(CameraMan.GetProgressText(playerId, comms)); - break; - case CustomRoles.NiceHacker: - ProgressText.Append(NiceHacker.GetProgressText(playerId, comms)); - break; - case CustomRoles.RiftMaker: - ProgressText.Append(RiftMaker.GetProgressText()); - break; - case CustomRoles.Ricochet: - ProgressText.Append(Ricochet.GetProgressText(playerId, comms)); - break; - case CustomRoles.Doormaster: - ProgressText.Append(Doormaster.GetProgressText(playerId, comms)); - break; - case CustomRoles.CopyCat: - ProgressText.Append(GetAbilityUseLimitDisplay(playerId)); - break; - case CustomRoles.PlagueBearer: - var plagued = PlagueBearer.PlaguedPlayerCount(playerId); - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.PlagueBearer).ShadeColor(0.25f), $"- {plagued.Item1}/{plagued.Item2}")); - break; - case CustomRoles.Doomsayer: - var doomsayerguess = Doomsayer.GuessedPlayerCount(playerId); - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Doomsayer).ShadeColor(0.25f), $"- {doomsayerguess.Item1}/{doomsayerguess.Item2}")); - break; - - case CustomRoles.Sniper: - ProgressText.Append(Sniper.GetBulletCount(playerId)); - break; - case CustomRoles.EvilTracker: - ProgressText.Append(EvilTracker.GetMarker(playerId)); - break; - case CustomRoles.TimeThief: - ProgressText.Append(TimeThief.GetProgressText(playerId)); - break; - case CustomRoles.Vulture: - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Vulture).ShadeColor(0.25f), $"- {(Vulture.BodyReportCount.GetValueOrDefault(playerId, 0))}/{Vulture.NumberOfReportsToWin.GetInt()}")); - break; - //case CustomRoles.Masochist: - // ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Masochist).ShadeColor(0.25f), $"- {(Main.MasochistKillMax.TryGetValue(playerId, out var count3) ? count3 : 0)}/{Options.MasochistKillMax.GetInt()}")); - // break; - case CustomRoles.QuickShooter: - ProgressText.Append(QuickShooter.GetShotLimit(playerId)); - break; - case CustomRoles.Cantankerous: - ProgressText.Append(Cantankerous.GetProgressText(playerId)); - break; - case CustomRoles.SwordsMan: - ProgressText.Append(SwordsMan.GetKillLimit(playerId)); - break; - case CustomRoles.Pelican: - ProgressText.Append(Pelican.GetProgressText(playerId)); - break; - //case CustomRoles.Counterfeiter: - // ProgressText.Append(Counterfeiter.GetSeelLimit(playerId)); - // break; - case CustomRoles.Tether: - ProgressText.Append(Tether.GetProgressText(playerId, comms)); - break; - case CustomRoles.Spy: - ProgressText.Append(Spy.GetProgressText(playerId, comms)); - break; - case CustomRoles.Aid: - ProgressText.Append(Aid.GetProgressText(playerId, comms)); - break; - case CustomRoles.Mafioso when !pc.IsModClient(): - ProgressText.Append(Mafioso.GetProgressText()); - break; - case CustomRoles.Consort: - ProgressText.Append(Consort.GetProgressText(playerId)); - break; - case CustomRoles.Drainer: - ProgressText.Append(Drainer.GetProgressText()); - break; - case CustomRoles.DonutDelivery when Options.CurrentGameMode != CustomGameMode.MoveAndStop: - ProgressText.Append(DonutDelivery.GetProgressText(playerId)); - break; - case CustomRoles.Gaulois: - ProgressText.Append(Gaulois.GetProgressText(playerId)); - break; - case CustomRoles.Escort: - ProgressText.Append(Escort.GetProgressText(playerId)); - break; - case CustomRoles.Pursuer: - ProgressText.Append(Pursuer.GetSeelLimit(playerId)); - break; - case CustomRoles.Gangster: - ProgressText.Append(Gangster.GetRecruitLimit(playerId)); - break; - case CustomRoles.Medic: - ProgressText.Append(Medic.GetSkillLimit(playerId)); - break; - case CustomRoles.CursedWolf: - int SpellCount = Main.CursedWolfSpellCount[playerId]; - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.CursedWolf), $"({SpellCount})")); - break; - case CustomRoles.Jinx: - int JinxSpellCount = Main.JinxSpellCount[playerId]; - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Jinx), $"({JinxSpellCount})")); - break; - case CustomRoles.Collector: - ProgressText.Append(Collector.GetProgressText(playerId)); - break; - case CustomRoles.Eraser: - ProgressText.Append(Eraser.GetProgressText(playerId)); - break; - //case CustomRoles.NiceEraser: - // ProgressText.Append(NiceEraser.GetProgressText(playerId)); - // break; - case CustomRoles.Hacker: - ProgressText.Append(Hacker.GetHackLimit(playerId)); - break; - case CustomRoles.KB_Normal: - ProgressText.Append(SoloKombatManager.GetDisplayScore(playerId)); - break; - case CustomRoles.Killer: - ProgressText.Append(FFAManager.GetDisplayScore(playerId)); - break; - case CustomRoles.Totocalcio: - ProgressText.Append(Totocalcio.GetProgressText(playerId)); - break; - case CustomRoles.Succubus: - ProgressText.Append(Succubus.GetCharmLimit()); - break; - //case CustomRoles.CursedSoul: - // ProgressText.Append(CursedSoul.GetCurseLimit()); - // break; - case CustomRoles.Monarch: - ProgressText.Append(Monarch.GetKnightLimit(playerId)); - break; - case CustomRoles.Deputy: - ProgressText.Append(Deputy.GetHandcuffLimit(playerId)); - break; - case CustomRoles.Virus: - ProgressText.Append(Virus.GetInfectLimit()); - break; - case CustomRoles.Ritualist: - ProgressText.Append(Ritualist.GetRitualCount(playerId)); - break; - case CustomRoles.Jackal: - if (Jackal.CanRecruitSidekick.GetBool()) - ProgressText.Append(Jackal.GetRecruitLimit(playerId)); - break; - case CustomRoles.Spiritcaller: - ProgressText.Append(Spiritcaller.GetSpiritLimit()); - break; - default: - //タスクテキスト - ProgressText.Append(GetTaskCount(playerId, comms)); - break; - } + ProgressText.Append(Main.PlayerStates[playerId].Role.GetProgressText(playerId, comms)); } catch (Exception ex) { @@ -1135,14 +898,7 @@ public static class Utils /// A list containing all PlayerControls within the specified range from the specified location public static PlayerControl[] GetPlayersInRadius(float radius, Vector2 from) { - var list = new List(); - foreach (PlayerControl tg in Main.AllAlivePlayerControls) - { - var dis = Vector2.Distance(from, tg.Pos()); - if (Pelican.IsEaten(tg.PlayerId) || Medic.ProtectList.Contains(tg.PlayerId) || tg.inVent) continue; - if (dis > radius) continue; - list.Add(tg); - } + var list = (from tg in Main.AllAlivePlayerControls let dis = Vector2.Distance(@from, tg.Pos()) where !Pelican.IsEaten(tg.PlayerId) && !Medic.ProtectList.Contains(tg.PlayerId) && !tg.inVent where !(dis > radius) select tg).ToList(); return [.. list]; } @@ -1185,7 +941,6 @@ public static class Utils public static void ShowAllActiveSettings(byte PlayerId = byte.MaxValue) { - var mapId = Main.NormalOptions.MapId; if (Options.HideGameSettings.GetBool() && PlayerId != byte.MaxValue) { SendMessage(GetString("Message.HideGameSettings"), PlayerId); @@ -1270,17 +1025,15 @@ public static class Utils } var sb = new StringBuilder(); - sb.AppendFormat("\n{0}: {1}", GetRoleName(CustomRoles.GM), Options.EnableGM.GetString().RemoveHtmlTags()); + sb.Append($"\n{GetRoleName(CustomRoles.GM)}: {Options.EnableGM.GetString().RemoveHtmlTags()}"); var impsb = new StringBuilder(); var neutralsb = new StringBuilder(); var crewsb = new StringBuilder(); var addonsb = new StringBuilder(); //int headCount = -1; - IList list = Enum.GetValues(typeof(CustomRoles)); - for (int i = 0; i < list.Count; i++) + foreach (var role in EnumHelper.GetAllValues()) { - CustomRoles role = (CustomRoles)list[i]; string mode = GetString($"Rate{role.GetMode()}"); if (role.IsEnable()) { @@ -1360,7 +1113,7 @@ public static class Utils sb.Append("<#ffffff>Role Summary:"); - List cloneRoles = new(Main.PlayerStates.Keys); + List cloneRoles = [..Main.PlayerStates.Keys]; foreach (byte id in Main.winnerList.ToArray()) { if (EndGamePatch.SummaryText[id].Contains("")) continue; @@ -1372,10 +1125,7 @@ public static class Utils { case CustomGameMode.SoloKombat: List<(int, byte)> list = []; - foreach (byte id in cloneRoles.ToArray()) - { - list.Add((SoloKombatManager.GetRankOfScore(id), id)); - } + list.AddRange(cloneRoles.ToArray().Select(id => (SoloKombatManager.GetRankOfScore(id), id))); list.Sort(); foreach ((int, byte) id in list.ToArray()) @@ -1386,10 +1136,7 @@ public static class Utils break; case CustomGameMode.FFA: List<(int, byte)> list2 = []; - foreach (byte id in cloneRoles.ToArray()) - { - list2.Add((FFAManager.GetRankOfScore(id), id)); - } + list2.AddRange(cloneRoles.ToArray().Select(id => (FFAManager.GetRankOfScore(id), id))); list2.Sort(); foreach ((int, byte) id in list2.ToArray()) @@ -1400,10 +1147,7 @@ public static class Utils break; case CustomGameMode.MoveAndStop: List<(int, byte)> list3 = []; - foreach (byte id in cloneRoles.ToArray()) - { - list3.Add((MoveAndStopManager.GetRankOfScore(id), id)); - } + list3.AddRange(cloneRoles.ToArray().Select(id => (MoveAndStopManager.GetRankOfScore(id), id))); list3.Sort(); foreach ((int, byte) id in list3.ToArray()) @@ -1414,10 +1158,7 @@ public static class Utils break; case CustomGameMode.HotPotato: List list4 = []; - foreach (byte id in cloneRoles.ToArray()) - { - list4.Add(id); - } + list4.AddRange(cloneRoles.ToArray()); foreach (byte id in list4.ToArray()) { @@ -1476,17 +1217,22 @@ public static class Utils bool isLovers = false; if (intro) { - foreach (CustomRoles role in SubRoles.ToArray()) + foreach (CustomRoles role in SubRoles) { - if (role is CustomRoles.NotAssigned or CustomRoles.LastImpostor) SubRoles.Remove(role); - if (role is CustomRoles.Lovers) + switch (role) { - SubRoles.Remove(role); - isLovers = true; + case CustomRoles.NotAssigned: + case CustomRoles.LastImpostor: + SubRoles.Remove(role); + break; + case CustomRoles.Lovers: + SubRoles.Remove(role); + isLovers = true; + break; } } - if (intro && isLovers) + if (isLovers) { //var RoleText = disableColor ? GetRoleName(CustomRoles.Lovers) : ColorString(GetRoleColor(CustomRoles.Lovers), GetRoleName(CustomRoles.Lovers)); sb.Append($"{ColorString(GetRoleColor(CustomRoles.Lovers), " ♥")}"); @@ -1816,14 +1562,7 @@ public static class Utils { if (pc.Is(CustomRoles.Terrorist)) { - if (Main.PlayerStates[pc.PlayerId].deathReason == PlayerState.DeathReason.Vote) - { - Main.PlayerStates[pc.PlayerId].deathReason = PlayerState.DeathReason.etc; - } - else - { - Main.PlayerStates[pc.PlayerId].deathReason = PlayerState.DeathReason.Suicide; - } + Main.PlayerStates[pc.PlayerId].deathReason = Main.PlayerStates[pc.PlayerId].deathReason == PlayerState.DeathReason.Vote ? PlayerState.DeathReason.etc : PlayerState.DeathReason.Suicide; } else if (!pc.Data.IsDead) { @@ -1935,6 +1674,7 @@ public static class Utils public static PlayerControl GetPlayerById(int PlayerId) { + // ReSharper disable once LoopCanBeConvertedToQuery ---- Leave it like this for better performance foreach (var pc in Main.AllPlayerControls) { if (pc.PlayerId == PlayerId) @@ -1996,16 +1736,15 @@ public static class Utils if (Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato) goto GameMode0; - if (Snitch.IsEnable) SelfMark.Append(Snitch.GetWarningArrow(seer)); + SelfMark.Append(Snitch.GetWarningArrow(seer)); if (seer.Is(CustomRoles.Lovers)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.Lovers), "♥")); - if (BallLightning.IsGhost(seer) && BallLightning.IsEnable) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■")); - if (Medic.IsEnable - && (Medic.InProtect(seer.PlayerId) || Medic.TempMarkProtected == seer.PlayerId) + if (BallLightning.IsGhost(seer)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■")); + if ((Medic.InProtect(seer.PlayerId) || Medic.TempMarkProtected == seer.PlayerId) && !seer.Is(CustomRoles.Medic) && (Medic.WhoCanSeeProtect.GetInt() == 0 || Medic.WhoCanSeeProtect.GetInt() == 2)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.Medic), " ●")); - if (Gamer.IsEnable) SelfMark.Append(Gamer.TargetMark(seer, seer)); - if (Sniper.IsEnable) SelfMark.Append(Sniper.GetShotNotify(seer.PlayerId)); + SelfMark.Append(Gamer.TargetMark(seer, seer)); + SelfMark.Append(Sniper.GetShotNotify(seer.PlayerId)); if (Blackmailer.ForBlackmailer.Contains(seer.PlayerId)) SelfMark.Append(ColorString(GetRoleColor(CustomRoles.Blackmailer), "╳")); GameMode0: @@ -2050,7 +1789,7 @@ public static class Utils SelfSuffix.Append(Ricochet.TargetText(seer.PlayerId)); break; case CustomRoles.Hitman: - SelfSuffix.Append(Hitman.GetTargetText()); + SelfSuffix.Append(Hitman.GetTargetText(seer.PlayerId)); break; case CustomRoles.Romantic: SelfSuffix.Append(Romantic.GetTargetText(seer.PlayerId)); @@ -2074,29 +1813,22 @@ public static class Utils SelfSuffix.Append(Vulture.GetTargetArrow(seer)); break; case CustomRoles.YinYanger when !seer.IsModClient(): - SelfSuffix.Append(YinYanger.ModeText); + SelfSuffix.Append(YinYanger.ModeText(seer)); break; case CustomRoles.FireWorks: SelfSuffix.Append(FireWorks.GetStateText(seer)); break; + case CustomRoles.HexMaster: case CustomRoles.Witch: SelfSuffix.Append(Witch.GetSpellModeText(seer, false, isForMeeting)); break; - case CustomRoles.HexMaster: - SelfSuffix.Append(HexMaster.GetHexModeText(seer, false, isForMeeting)); - break; + case CustomRoles.Monitor: case CustomRoles.AntiAdminer: if (AntiAdminer.IsAdminWatch) SelfSuffix.Append(GetString("AntiAdminerAD")); if (AntiAdminer.IsVitalWatch) SelfSuffix.Append(GetString("AntiAdminerVI")); if (AntiAdminer.IsDoorLogWatch) SelfSuffix.Append(GetString("AntiAdminerDL")); if (AntiAdminer.IsCameraWatch) SelfSuffix.Append(GetString("AntiAdminerCA")); break; - case CustomRoles.Monitor: - if (Monitor.IsAdminWatch) SelfSuffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("AdminWarning"))); - if (Monitor.IsVitalWatch) SelfSuffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("VitalsWarning"))); - if (Monitor.IsDoorLogWatch) SelfSuffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("DoorlogWarning"))); - if (Monitor.IsCameraWatch) SelfSuffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("CameraWarning"))); - break; case CustomRoles.Bloodhound: SelfSuffix.Append(Bloodhound.GetTargetArrow(seer)); break; @@ -2116,12 +1848,10 @@ public static class Utils } else { - if (Witch.IsEnable) SelfMark.Append(Witch.GetSpelledMark(seer.PlayerId, isForMeeting)); - if (HexMaster.IsEnable) SelfMark.Append(HexMaster.GetHexedMark(seer.PlayerId, isForMeeting)); + SelfMark.Append(Witch.GetSpelledMark(seer.PlayerId, isForMeeting)); } - if (Deathpact.IsEnable) - SelfSuffix.Append(Deathpact.GetDeathpactPlayerArrow(seer)); + SelfSuffix.Append(Deathpact.GetDeathpactPlayerArrow(seer)); GameMode: @@ -2146,30 +1876,25 @@ public static class Utils if (!isForMeeting && MeetingStates.FirstMeeting && Options.ChangeNameToRoleInfo.GetBool() && Options.CurrentGameMode is not CustomGameMode.FFA and not CustomGameMode.MoveAndStop and not CustomGameMode.HotPotato) { - if (seer.GetCustomRole().IsCrewmate() && !seer.Is(CustomRoles.Madmate)) + if (seer.GetCustomRole().IsMadmate() || seer.Is(CustomRoles.Madmate)) + { + SeerRealName = $"{GetString("YouAreMadmate")}\n{seer.GetRoleInfo()}"; + } + + else if (seer.GetCustomRole().IsCrewmate()) { SeerRealName = $"{GetString("YouAreCrewmate")}\n{seer.GetRoleInfo()}"; } - if (seer.GetCustomRole().IsImpostor()) + else if (seer.GetCustomRole().IsImpostor()) { SeerRealName = $"\n{seer.GetRoleInfo()}"; } - if (seer.GetCustomRole().IsNeutral() && !seer.GetCustomRole().IsMadmate()) + else if (seer.GetCustomRole().IsNeutral()) { SeerRealName = $"{GetString("YouAreNeutral")}\n{seer.GetRoleInfo()}"; } - - if (seer.GetCustomRole().IsMadmate()) - { - SeerRealName = $"{GetString("YouAreMadmate")}\n{seer.GetRoleInfo()}"; - } - - if (seer.Is(CustomRoles.Madmate)) - { - SeerRealName = $"{GetString("YouAreMadmate")}\n{seer.GetRoleInfo()}"; - } } // Combine seer's job title and SelfTaskText with seer's player name and SelfMark @@ -2179,15 +1904,12 @@ public static class Utils if (Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato) goto GameMode2; - switch (seer.GetCustomRole()) + SelfName = seer.GetCustomRole() switch { - case CustomRoles.Arsonist when seer.IsDouseDone(): - SelfName = $"{ColorString(seer.GetRoleColor(), GetString("EnterVentToWin"))}"; - break; - case CustomRoles.Revolutionist when seer.IsDrawDone(): - SelfName = $">{ColorString(seer.GetRoleColor(), string.Format(GetString("EnterVentWinCountDown"), Main.RevolutionistCountdown.GetValueOrDefault(seer.PlayerId, 10)))}"; - break; - } + CustomRoles.Arsonist when seer.IsDouseDone() => $"{ColorString(seer.GetRoleColor(), GetString("EnterVentToWin"))}", + CustomRoles.Revolutionist when seer.IsDrawDone() => $">{ColorString(seer.GetRoleColor(), string.Format(GetString("EnterVentWinCountDown"), Main.RevolutionistCountdown.GetValueOrDefault(seer.PlayerId, 10)))}", + _ => SelfName + }; if (Pelican.IsEaten(seer.PlayerId)) SelfName = $"{ColorString(GetRoleColor(CustomRoles.Pelican), GetString("EatenByPelican"))}"; @@ -2197,7 +1919,7 @@ public static class Utils SelfName = name; // Devourer - if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.PlayerSkinsCosumed.Any(a => a.Value.Contains(seer.PlayerId)) && !CamouflageIsForMeeting) + if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.playerIdList.Any(x => Main.PlayerStates[x].Role is Devourer { IsEnable: true } dv && dv.PlayerSkinsCosumed.Contains(seer.PlayerId)) && !CamouflageIsForMeeting) SelfName = GetString("DevouredName"); // Camouflage if (((IsActive(SystemTypes.Comms) && Options.CommsCamouflage.GetBool() && (Main.NormalOptions.MapId != 5 || !Options.CommsCamouflageDisableOnFungle.GetBool())) || Camouflager.IsActive) && !CamouflageIsForMeeting) @@ -2243,16 +1965,15 @@ public static class Utils if (Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato) goto BeforeEnd2; - if (Witch.IsEnable) TargetMark.Append(Witch.GetSpelledMark(target.PlayerId, isForMeeting)); - if (HexMaster.IsEnable) TargetMark.Append(HexMaster.GetHexedMark(target.PlayerId, isForMeeting)); + TargetMark.Append(Witch.GetSpelledMark(target.PlayerId, isForMeeting)); if (target.Is(CustomRoles.SuperStar) && Options.EveryOneKnowSuperStar.GetBool()) TargetMark.Append(ColorString(GetRoleColor(CustomRoles.SuperStar), "★")); - if (BallLightning.IsGhost(target) && BallLightning.IsEnable) + if (BallLightning.IsGhost(target)) TargetMark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■")); - if (Snitch.IsEnable) TargetMark.Append(Snitch.GetWarningMark(seer, target)); + TargetMark.Append(Snitch.GetWarningMark(seer, target)); if ((seer.Is(CustomRoles.Lovers) && target.Is(CustomRoles.Lovers)) || (seer.Data.IsDead && !seer.Is(CustomRoles.Lovers) && target.Is(CustomRoles.Lovers))) @@ -2304,13 +2025,13 @@ public static class Utils break; case CustomRoles.Analyzer: - if (Analyzer.CurrentTarget.ID == target.PlayerId) + if ((Main.PlayerStates[seer.PlayerId].Role as Analyzer).CurrentTarget.ID == target.PlayerId) { TargetMark.Append($"○"); } break; - case CustomRoles.Puppeteer when Main.PuppeteerList.ContainsValue(seer.PlayerId) && Main.PuppeteerList.ContainsKey(target.PlayerId): + case CustomRoles.Puppeteer when Puppeteer.PuppeteerList.ContainsValue(seer.PlayerId) && Puppeteer.PuppeteerList.ContainsKey(target.PlayerId): TargetMark.Append($"◆"); break; } @@ -2344,7 +2065,6 @@ public static class Utils Romantic.KnowRole(seer, target) || Lawyer.KnowRole(seer, target) || EvilDiviner.IsShowTargetRole(seer, target) || - Ritualist.IsShowTargetRole(seer, target) || Executioner.KnowRole(seer, target) || Succubus.KnowRole(seer, target) || Necromancer.KnowRole(seer, target) || @@ -2395,10 +2115,10 @@ public static class Utils case CustomRoles.NiceSwapper when seer.IsAlive() && target.IsAlive() && isForMeeting: TargetPlayerName = $"{ColorString(GetRoleColor(CustomRoles.NiceSwapper), target.PlayerId.ToString())} {TargetPlayerName}"; break; - case CustomRoles.HeadHunter when HeadHunter.Targets.Contains(target.PlayerId) && seer.IsAlive(): + case CustomRoles.HeadHunter when (Main.PlayerStates[seer.PlayerId].Role as HeadHunter).Targets.Contains(target.PlayerId) && seer.IsAlive(): TargetPlayerName = $"{TargetPlayerName}"; break; - case CustomRoles.BountyHunter when BountyHunter.GetTarget(seer) == target.PlayerId && seer.IsAlive(): + case CustomRoles.BountyHunter when (Main.PlayerStates[seer.PlayerId].Role as BountyHunter).GetTarget(seer) == target.PlayerId && seer.IsAlive(): TargetPlayerName = $"{TargetPlayerName}"; break; case CustomRoles.ParityCop when seer.IsAlive() && target.IsAlive() && GuesserIsForMeeting: @@ -2524,7 +2244,7 @@ public static class Utils TargetDeathReason = $"\n({ColorString(GetRoleColor(CustomRoles.Doctor), GetVitalText(target.PlayerId))})"; // Devourer - if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.PlayerSkinsCosumed.Any(a => a.Value.Contains(target.PlayerId)) && !CamouflageIsForMeeting) + if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.playerIdList.Any(x => Main.PlayerStates[x].Role is Devourer { IsEnable: true } dv && dv.PlayerSkinsCosumed.Contains(seer.PlayerId)) && !CamouflageIsForMeeting) TargetPlayerName = GetString("DevouredName"); // Camouflage @@ -2578,492 +2298,6 @@ public static class Utils GameOptionsSender.SendAllGameOptions(); } - public static void AddRoles(byte id, CustomRoles role) - { - switch (role) - { - case CustomRoles.BountyHunter: - BountyHunter.Add(id); - break; - case CustomRoles.SerialKiller: - SerialKiller.Add(id); - break; - case CustomRoles.Bandit: - Bandit.Add(id); - break; - case CustomRoles.Witch: - Witch.Add(id); - break; - case CustomRoles.HexMaster: - HexMaster.Add(id); - break; - case CustomRoles.NiceSwapper: - NiceSwapper.Add(id); - break; - case CustomRoles.Crusader: - Crusader.Add(id); - id.SetAbilityUseLimit(Crusader.SkillLimitOpt.GetInt()); - break; - case CustomRoles.FireWorks: - FireWorks.Add(id); - break; - case CustomRoles.Agitater: - Agitater.Add(id); - break; - case CustomRoles.Randomizer: - Randomizer.Add(id); - break; - case CustomRoles.TimeThief: - TimeThief.Add(id); - break; - case CustomRoles.Sniper: - Sniper.Add(id); - break; - case CustomRoles.Vampire: - Vampire.Add(id); - break; - case CustomRoles.SwordsMan: - SwordsMan.Add(id); - break; - case CustomRoles.Farseer: - foreach (PlayerControl ar in Main.AllPlayerControls) - { - Main.isRevealed.Add((id, ar.PlayerId), false); - } - - Farseer.RandomRole.Add(id, Farseer.GetRandomCrewRoleString()); - Farseer.Add(id); - break; - case CustomRoles.Executioner: - Executioner.Add(id); - break; - case CustomRoles.Lawyer: - Lawyer.Add(id); - break; - case CustomRoles.Blackmailer: - Blackmailer.Add(id); - break; - case CustomRoles.Crewpostor: - Crewpostor.TasksDone[id] = 0; - break; - case CustomRoles.Doppelganger: - Doppelganger.Add(id); - break; - case CustomRoles.Jackal: - Jackal.Add(id); - break; - case CustomRoles.Sidekick: - Sidekick.Add(id); - break; - case CustomRoles.Cleanser: - Cleanser.Add(id); - break; - case CustomRoles.Pickpocket: - Pickpocket.Add(id); - break; - case CustomRoles.Jailor: - Jailor.Add(id); - break; - case CustomRoles.Monitor: - Monitor.Add(id); - break; - case CustomRoles.Poisoner: - Poisoner.Add(id); - break; - case CustomRoles.Sheriff: - Sheriff.Add(id); - break; - case CustomRoles.CopyCat: - CopyCat.Add(id); - break; - case CustomRoles.QuickShooter: - QuickShooter.Add(id); - break; - case CustomRoles.SabotageMaster: - SabotageMaster.Add(id); - break; - case CustomRoles.EvilTracker: - EvilTracker.Add(id); - break; - case CustomRoles.Snitch: - Snitch.Add(id); - break; - case CustomRoles.AntiAdminer: - AntiAdminer.Add(id); - break; - case CustomRoles.TimeManager: - TimeManager.Add(id); - break; - case CustomRoles.Pelican: - Pelican.Add(id); - break; - case CustomRoles.Tether: - Tether.Add(id); - break; - case CustomRoles.Benefactor: - Benefactor.Add(id); - break; - case CustomRoles.Librarian: - Librarian.Add(id); - break; - case CustomRoles.Aid: - Aid.Add(id); - break; - case CustomRoles.Escort: - Escort.Add(id); - break; - case CustomRoles.Marshall: - Marshall.Add(id); - break; - case CustomRoles.Consort: - Consort.Add(id); - break; - case CustomRoles.Drainer: - Drainer.Add(id); - break; - case CustomRoles.DonutDelivery: - DonutDelivery.Add(id); - break; - case CustomRoles.Rabbit: - Rabbit.Add(id); - break; - case CustomRoles.Gaulois: - Gaulois.Add(id); - break; - case CustomRoles.Analyzer: - Analyzer.Add(id); - break; - case CustomRoles.Pursuer: - Pursuer.Add(id); - break; - case CustomRoles.Gangster: - Gangster.Add(id); - break; - case CustomRoles.Medic: - Medic.Add(id); - break; - case CustomRoles.EvilDiviner: - EvilDiviner.Add(id); - break; - case CustomRoles.Kamikaze: - Kamikaze.Add(id); - break; - case CustomRoles.Ritualist: - Ritualist.Add(id); - break; - case CustomRoles.Divinator: - Divinator.Add(id); - break; - case CustomRoles.Ricochet: - Ricochet.Add(id); - break; - case CustomRoles.Doormaster: - Doormaster.Add(id); - break; - case CustomRoles.Oracle: - Oracle.Add(id); - break; - case CustomRoles.Gamer: - Gamer.Add(id); - break; - case CustomRoles.BallLightning: - BallLightning.Add(id); - break; - case CustomRoles.DarkHide: - DarkHide.Add(id); - break; - case CustomRoles.Greedier: - Greedier.Add(id); - break; - case CustomRoles.Glitch: - Glitch.Add(id); - break; - case CustomRoles.Imitator: - Imitator.Add(id); - break; - case CustomRoles.Ignitor: - Ignitor.Add(id); - break; - case CustomRoles.Collector: - Collector.Add(id); - break; - case CustomRoles.Jinx: - Main.JinxSpellCount[id] = Jinx.JinxSpellTimes.GetInt(); - Jinx.Add(id); - break; - case CustomRoles.Eraser: - Eraser.Add(id); - break; - case CustomRoles.Spy: - Spy.Add(id); - break; - case CustomRoles.NiceEraser: - NiceEraser.Add(id); - break; - case CustomRoles.Assassin: - Assassin.Add(id); - break; - case CustomRoles.Undertaker: - Undertaker.Add(id); - break; - case CustomRoles.Sans: - Sans.Add(id); - break; - case CustomRoles.Juggernaut: - Juggernaut.Add(id); - break; - case CustomRoles.Hacker: - Hacker.Add(id); - break; - case CustomRoles.NiceHacker: - NiceHacker.Add(id); - break; - case CustomRoles.Psychic: - Psychic.Add(id); - break; - case CustomRoles.Hangman: - Hangman.Add(id); - break; - case CustomRoles.Judge: - Judge.Add(id); - break; - case CustomRoles.Councillor: - Councillor.Add(id); - break; - case CustomRoles.Camouflager: - Camouflager.Add(id); - break; - case CustomRoles.Twister: - Twister.Add(id); - break; - case CustomRoles.Mortician: - Mortician.Add(id); - break; - case CustomRoles.Tracefinder: - Tracefinder.Add(id); - break; - case CustomRoles.Mediumshiper: - Mediumshiper.Add(id); - break; - case CustomRoles.Swooper: - Swooper.Add(id); - break; - case CustomRoles.Wraith: - Wraith.Add(id); - break; - case CustomRoles.Chameleon: - Chameleon.Add(id); - break; - case CustomRoles.BloodKnight: - BloodKnight.Add(id); - break; - case CustomRoles.Totocalcio: - Totocalcio.Add(id); - break; - case CustomRoles.Romantic: - Romantic.Add(id); - break; - case CustomRoles.VengefulRomantic: - VengefulRomantic.Add(id); - break; - case CustomRoles.RuthlessRomantic: - RuthlessRomantic.Add(id); - break; - case CustomRoles.Succubus: - Succubus.Add(id); - break; - //case CustomRoles.CursedSoul: - // CursedSoul.Add(id); - // break; - case CustomRoles.Amnesiac: - Amnesiac.Add(id); - break; - case CustomRoles.Monarch: - Monarch.Add(id); - break; - case CustomRoles.Deputy: - Deputy.Add(id); - break; - case CustomRoles.Chronomancer: - Chronomancer.Add(id); - break; - case CustomRoles.Nullifier: - Nullifier.Add(id); - break; - case CustomRoles.Virus: - Virus.Add(id); - break; - case CustomRoles.Wildling: - Wildling.Add(id); - break; - case CustomRoles.Bloodhound: - Bloodhound.Add(id); - break; - case CustomRoles.Tracker: - Tracker.Add(id); - break; - case CustomRoles.Merchant: - Merchant.Add(id); - break; - case CustomRoles.NSerialKiller: - NSerialKiller.Add(id); - break; - case CustomRoles.SoulHunter: - SoulHunter.Add(id); - break; - case CustomRoles.Enderman: - Enderman.Add(id); - break; - case CustomRoles.Sentinel: - Sentinel.Add(id); - break; - case CustomRoles.Mycologist: - Mycologist.Add(id); - break; - case CustomRoles.Bubble: - Bubble.Add(id); - break; - case CustomRoles.Tornado: - Tornado.Add(id); - break; - case CustomRoles.Hookshot: - Hookshot.Add(id); - break; - case CustomRoles.Sprayer: - Sprayer.Add(id); - break; - case CustomRoles.PlagueDoctor: - PlagueDoctor.Add(id); - break; - case CustomRoles.Penguin: - Penguin.Add(id); - break; - case CustomRoles.Stealth: - Stealth.Add(id); - break; - case CustomRoles.Postman: - Postman.Add(id); - break; - case CustomRoles.Mafioso: - Mafioso.Add(id); - break; - case CustomRoles.Magician: - Magician.Add(id); - break; - case CustomRoles.WeaponMaster: - WeaponMaster.Add(id); - break; - case CustomRoles.Reckless: - Reckless.Add(id); - break; - case CustomRoles.Eclipse: - Eclipse.Add(id); - break; - case CustomRoles.Pyromaniac: - Pyromaniac.Add(id); - break; - case CustomRoles.Vengeance: - Vengeance.Add(id); - break; - case CustomRoles.HeadHunter: - HeadHunter.Add(id); - break; - case CustomRoles.Werewolf: - Werewolf.Add(id); - break; - case CustomRoles.Traitor: - Traitor.Add(id); - break; - case CustomRoles.Maverick: - Maverick.Add(id); - break; - case CustomRoles.Dazzler: - Dazzler.Add(id); - break; - case CustomRoles.YinYanger: - YinYanger.Add(id); - break; - case CustomRoles.Cantankerous: - Cantankerous.Add(id); - break; - case CustomRoles.Duellist: - Duellist.Add(id); - break; - case CustomRoles.Druid: - Druid.Add(id); - break; - case CustomRoles.Convener: - Convener.Add(id); - break; - case CustomRoles.FFF: - FFF.Add(id); - break; - case CustomRoles.Sapper: - Sapper.Add(id); - break; - case CustomRoles.CameraMan: - CameraMan.Add(id); - break; - case CustomRoles.Hitman: - Hitman.Add(id); - break; - case CustomRoles.Enigma: - Enigma.Add(id); - break; - case CustomRoles.Gambler: - Gambler.Add(id); - break; - case CustomRoles.RiftMaker: - RiftMaker.Add(id); - break; - case CustomRoles.Mastermind: - Mastermind.Add(id); - break; - case CustomRoles.Addict: - Addict.Add(id); - break; - case CustomRoles.Alchemist: - Alchemist.Add(id); - break; - case CustomRoles.Deathpact: - Deathpact.Add(id); - break; - case CustomRoles.Morphling: - Morphling.Add(id); - break; - case CustomRoles.Devourer: - Devourer.Add(id); - break; - case CustomRoles.Spiritualist: - Spiritualist.Add(id); - break; - case CustomRoles.Vulture: - Vulture.Add(id); - break; - case CustomRoles.GuessManager: - GuessManagerRole.Add(id); - break; - case CustomRoles.PlagueBearer: - PlagueBearer.Add(id); - break; - case CustomRoles.ParityCop: - ParityCop.Add(id); - break; - case CustomRoles.Spiritcaller: - Spiritcaller.Add(id); - break; - case CustomRoles.Lurker: - Lurker.Add(id); - break; - case CustomRoles.Doomsayer: - Doomsayer.Add(id); - break; - case CustomRoles.Disperser: - Disperser.Add(id); - break; - } - } - public static void AddAbilityCD(CustomRoles role, byte playerId, bool includeDuration = true) { if (role.UsesPetInsteadOfKill()) @@ -3092,7 +2326,7 @@ public static class Utils CustomRoles.Tornado => Tornado.TornadoCooldown.GetInt(), CustomRoles.Sentinel => Sentinel.PatrolCooldown.GetInt(), CustomRoles.Sniper => Options.DefaultShapeshiftCooldown.GetInt(), - CustomRoles.Assassin => Assassin.AssassinateCooldown.GetInt(), + CustomRoles.Assassin => Assassin.AssassinateCooldownOpt.GetInt(), CustomRoles.Undertaker => Undertaker.AssassinateCooldown.GetInt(), CustomRoles.Bomber => Options.BombCooldown.GetInt(), CustomRoles.Nuker => Options.NukeCooldown.GetInt(), @@ -3130,8 +2364,14 @@ public static class Utils } if (!pc.IsModClient()) pc.ReactorFlash(0.2f); // This should fix black screens + + if (Options.UsePets.GetBool()) pc.AddAbilityCD(includeDuration: false); + + Main.PlayerStates[pc.PlayerId].Role.AfterMeetingTasks(); } + CopyCat.ResetRole(); + if (Options.DiseasedCDReset.GetBool()) { var array = Main.KilledDiseased.Keys.ToArray(); @@ -3156,42 +2396,11 @@ public static class Utils Main.KilledAntidote.Clear(); } - if (Blackmailer.IsEnable) Blackmailer.ForBlackmailer.Clear(); - if (Glitch.IsEnable) Glitch.AfterMeetingTasks(); - if (Swooper.IsEnable) Swooper.AfterMeetingTasks(); - if (Wraith.IsEnable) Wraith.AfterMeetingTasks(); - if (Werewolf.IsEnable) Werewolf.AfterMeetingTasks(); - if (Chameleon.IsEnable) Chameleon.AfterMeetingTasks(); - if (NiceEraser.IsEnable) NiceEraser.AfterMeetingTasks(); - if (Eraser.IsEnable) Eraser.AfterMeetingTasks(); - if (Cleanser.IsEnable) Cleanser.AfterMeetingTasks(); - if (Randomizer.IsEnable) Randomizer.AfterMeetingTasks(); - if (BountyHunter.IsEnable) BountyHunter.AfterMeetingTasks(); - if (EvilTracker.IsEnable) EvilTracker.AfterMeetingTasks(); - if (SerialKiller.IsEnable()) SerialKiller.AfterMeetingTasks(); - if (Spiritualist.IsEnable) Spiritualist.AfterMeetingTasks(); - if (Mycologist.IsEnable) Mycologist.AfterMeetingTasks(); - if (Sprayer.IsEnable) Sprayer.AfterMeetingTasks(); - if (PlagueDoctor.IsEnable) PlagueDoctor.AfterMeetingTasks(); - if (SoulHunter.IsEnable) SoulHunter.AfterMeetingTasks(); - if (Penguin.IsEnable) Penguin.AfterMeetingTasks(); - if (Chronomancer.IsEnable) Chronomancer.OnReportDeadBody(); - if (Benefactor.IsEnable) Benefactor.AfterMeetingTasks(); - if (Vulture.IsEnable) Vulture.AfterMeetingTasks(); - //if (Baker.IsEnable()) Baker.AfterMeetingTasks(); - if (CopyCat.IsEnable()) CopyCat.AfterMeetingTasks(); - //Pirate.AfterMeetingTask(); + Blackmailer.ForBlackmailer.Clear(); + Damocles.AfterMeetingTasks(); Stressed.AfterMeetingTasks(); - if (Options.UsePets.GetBool()) - { - foreach (PlayerControl pc in Main.AllAlivePlayerControls) - { - pc.AddAbilityCD(includeDuration: false); - } - } - if (Options.AirshipVariableElectrical.GetBool()) AirshipElectricalDoors.Initialize(); @@ -3213,7 +2422,7 @@ public static class Utils { case CustomRoles.Terrorist: Logger.Info(target?.Data?.PlayerName + "はTerroristだった", "MurderPlayer"); - CheckTerroristWin(target.Data); + CheckTerroristWin(target?.Data); break; case CustomRoles.Executioner: if (Executioner.Target.ContainsKey(target.PlayerId)) @@ -3261,6 +2470,8 @@ public static class Utils break; } + if (target == null) return; + Randomizer.OnAnyoneDeath(target); if (Romantic.PartnerId == target.PlayerId) @@ -3270,16 +2481,15 @@ public static class Utils Executioner.ChangeRoleByTarget(target); if (Lawyer.Target.ContainsValue(target.PlayerId)) Lawyer.ChangeRoleByTarget(target); - if (Postman.Target == target.PlayerId) - Postman.CheckAndResetTargets(target, isDeath: true); - if (Hitman.targetId == target.PlayerId) - Hitman.targetId = byte.MaxValue; - if (Hacker.IsEnable) Hacker.AddDeadBody(target); - if (Mortician.IsEnable) Mortician.OnPlayerDead(target); - if (Bloodhound.IsEnable) Bloodhound.OnPlayerDead(target); - if (Tracefinder.IsEnable) Tracefinder.OnPlayerDead(target); - if (Vulture.IsEnable) Vulture.OnPlayerDead(target); + Postman.CheckAndResetTargets(target, isDeath: true); + Hitman.CheckAndResetTargets(); + + Hacker.AddDeadBody(target); + Mortician.OnPlayerDead(target); + Bloodhound.OnPlayerDead(target); + Tracefinder.OnPlayerDead(target); + Vulture.OnPlayerDead(target); FixedUpdatePatch.LoversSuicide(target.PlayerId, onMeeting); } @@ -3323,7 +2533,7 @@ public static class Utils var player = GetPlayerById(num); return num switch { - < 15 when player != null => player?.GetNameWithRole().RemoveHtmlTags(), + < 15 when player != null => player.GetNameWithRole().RemoveHtmlTags(), 253 => "Skip", 254 => "None", 255 => "Dead", @@ -3333,15 +2543,11 @@ public static class Utils public static string PadRightV2(this object text, int num) { - int bc = 0; var t = text.ToString(); - for (int i = 0; i < t.Length; i++) - { - char c = t[i]; - bc += Encoding.GetEncoding("UTF-8").GetByteCount(c.ToString()) == 1 ? 1 : 2; - } + if (t == null) return string.Empty; + int bc = t.Sum(c => Encoding.GetEncoding("UTF-8").GetByteCount(c.ToString()) == 1 ? 1 : 2); - return t?.PadRight(Mathf.Max(num - (bc - t.Length), 0)); + return t.PadRight(Mathf.Max(num - (bc - t.Length), 0)); } public static void DumpLog() @@ -3350,7 +2556,7 @@ public static class Utils string t = DateTime.Now.ToString("yyyy-MM-dd_HH.mm.ss"); string filename = $"{f}TOHE-v{Main.PluginVersion}-{t}.log"; if (!Directory.Exists(f)) Directory.CreateDirectory(f); - FileInfo file = new(@$"{Environment.CurrentDirectory}/BepInEx/LogOutput.log"); + FileInfo file = new($"{Environment.CurrentDirectory}/BepInEx/LogOutput.log"); file.CopyTo(filename); if (PlayerControl.LocalPlayer != null) HudManager.Instance?.Chat?.AddChat(PlayerControl.LocalPlayer, string.Format(GetString("Message.DumpfileSaved"), $"TOHE+ v{Main.PluginVersion} {t}.log")); @@ -3398,11 +2604,10 @@ public static class Utils var name = Main.AllPlayerNames[id].RemoveHtmlTags().Replace("\r\n", string.Empty); if (id == PlayerControl.LocalPlayer.PlayerId) name = DataManager.player.Customization.Name; else name = GetPlayerById(id)?.Data.PlayerName ?? name; - var taskState = Main.PlayerStates?[id].TaskState; + var taskState = Main.PlayerStates[id].TaskState; string TaskCount; if (taskState.hasTasks) { - Color TextColor; var info = GetPlayerInfoById(id); var TaskCompleteColor = HasTasks(info) ? Color.green : Color.cyan; //タスク完了後の色 var NonCompleteColor = HasTasks(info) ? Color.yellow : Color.white; //カウントされない人外は白色 @@ -3414,7 +2619,7 @@ public static class Utils if (Main.PlayerStates.TryGetValue(id, out var ps) && ps.MainRole == CustomRoles.Crewpostor) NormalColor = Color.red; - TextColor = NormalColor; + Color TextColor = NormalColor; string Completed = $"{taskState.CompletedTasksCount}"; TaskCount = ColorString(TextColor, $" ({Completed}/{taskState.AllTasksCount})"); } @@ -3427,9 +2632,7 @@ public static class Utils switch (Options.CurrentGameMode) { case CustomGameMode.SoloKombat: - if (TranslationController.Instance.currentLanguage.languageID is SupportedLangs.SChinese or SupportedLangs.TChinese) - summary = $"{GetProgressText(id)}\t{ColorString(Main.PlayerColors[id], name)}"; - else summary = $"{ColorString(Main.PlayerColors[id], name)}{GetProgressText(id)}"; + summary = TranslationController.Instance.currentLanguage.languageID is SupportedLangs.SChinese or SupportedLangs.TChinese ? $"{GetProgressText(id)}\t{ColorString(Main.PlayerColors[id], name)}" : $"{ColorString(Main.PlayerColors[id], name)}{GetProgressText(id)}"; if (GetProgressText(id).Trim() == string.Empty) return string.Empty; break; case CustomGameMode.FFA: @@ -3515,7 +2718,7 @@ public static class Utils hud.StartCoroutine(Effects.Lerp(duration, new Action(t => { - obj.SetActive(t != 1f); + obj.SetActive(Math.Abs(t - 1f) > 0.1f); obj.GetComponent().color = new(color.r, color.g, color.b, Mathf.Clamp01((-2f * Mathf.Abs(t - 0.5f) + 1) * color.a / 2)); //アルファ値を0→目標→0に変化させる }))); } @@ -3547,7 +2750,7 @@ public static class Utils var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(path); var texture = new Texture2D(1, 1, TextureFormat.ARGB32, false); using MemoryStream ms = new(); - stream.CopyTo(ms); + stream?.CopyTo(ms); ImageConversion.LoadImage(texture, ms.ToArray(), false); return texture; } diff --git a/Modules/Zoom.cs b/Modules/Zoom.cs index 0438c544e..f82e3b96d 100644 --- a/Modules/Zoom.cs +++ b/Modules/Zoom.cs @@ -1,6 +1,6 @@ -using System; +using HarmonyLib; +using System; using System.Collections.Generic; -using HarmonyLib; using UnityEngine; namespace TOHE; @@ -11,6 +11,7 @@ namespace TOHE; public static class Zoom { private static bool ResetButtons; + public static void Postfix() { //if (PlayerControl.LocalPlayer.Is(RoleType.Impostor) && Options.OperateVisibilityImpostor.GetBool()) return; @@ -25,8 +26,8 @@ public static class Zoom { SetZoomSize(times: false); } - } + if (Input.mouseScrollDelta.y < 0) { if (GameStates.IsDead || GameStates.IsFreePlay || DebugModeManager.AmDebugger || GameStates.IsLobby || @@ -38,14 +39,12 @@ public static class Zoom } } } + Flag.NewFlag("Zoom"); } else { - Flag.Run(() => - { - SetZoomSize(reset: true); - }, "Zoom"); + Flag.Run(() => { SetZoomSize(reset: true); }, "Zoom"); } } @@ -65,6 +64,7 @@ public static class Zoom Camera.main.orthographicSize *= size; HudManager.Instance.UICamera.orthographicSize *= size; } + DestroyableSingleton.Instance?.ShadowQuad?.gameObject?.SetActive((reset || Camera.main.orthographicSize == 3.0f) && PlayerControl.LocalPlayer.IsAlive()); if (ResetButtons) @@ -82,6 +82,7 @@ public static class Flag { private static readonly List OneTimeList = []; private static readonly List FirstRunList = []; + public static void Run(Action action, string type, bool firstrun = false) { if (OneTimeList.Contains(type) || (firstrun && !FirstRunList.Contains(type))) @@ -90,8 +91,8 @@ public static class Flag OneTimeList.Remove(type); action(); } - } + public static void NewFlag(string type) { if (!OneTimeList.Contains(type)) OneTimeList.Add(type); diff --git a/Patches/AirShipElectricalDoors.cs b/Patches/AirShipElectricalDoors.cs index 5f992875b..3891ca091 100644 --- a/Patches/AirShipElectricalDoors.cs +++ b/Patches/AirShipElectricalDoors.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using HarmonyLib; +using System.Collections.Generic; namespace TOHE; @@ -13,6 +13,7 @@ public class AirshipElectricalDoors if (Main.NormalOptions.MapId != 4) return; Instance.Initialize(); } + public static byte[] GetClosedDoors() { List DoorsArray = []; @@ -23,6 +24,7 @@ public class AirshipElectricalDoors if (door != null && !door.IsOpen) DoorsArray.Add(i); } + return DoorsArray?.ToArray(); } // 0: BottomRightHort @@ -38,10 +40,11 @@ public class AirshipElectricalDoors // 10: LeftDoorTop // 11: LeftDoorBottom } + [HarmonyPatch(typeof(ElectricalDoors), nameof(ElectricalDoors.Initialize))] class ElectricalDoorsInitializePatch { - public static void Postfix(/*ElectricalDoors __instance*/) + public static void Postfix( /*ElectricalDoors __instance*/) { if (!GameStates.IsInGame) return; var closedoors = string.Empty; @@ -57,6 +60,7 @@ class ElectricalDoorsInitializePatch else closedoors += $", {num}"; } + Logger.Info($"Closed Doors: {closedoors}", "ElectricalDoors Initialize"); } } \ No newline at end of file diff --git a/Patches/AnnouncementPatch.cs b/Patches/AnnouncementPatch.cs index 315d921ce..e02209018 100644 --- a/Patches/AnnouncementPatch.cs +++ b/Patches/AnnouncementPatch.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using AmongUs.Data; +using AmongUs.Data; using AmongUs.Data.Player; using Assets.InnerNet; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; +using System; +using System.Collections.Generic; +using System.Linq; namespace TOHE; @@ -35,6 +35,7 @@ public class ModNews }; } } + [HarmonyPatch] public class ModNewsHistory { @@ -53,17 +54,13 @@ public class ModNewsHistory SubTitle = "★★★★Another big update, maybe bigger?★★★★", ShortTitle = "★TOHE v2.5.0", Text = "Welcome to TOHE v2.5.0.\n\nSupport for Among Us v2023.7.11 and v2023.7.12\n" - - + "\n【Base】\n - Base on TOH v4.1.2\r\n" - + "\n【Fixes】\n - Various bug fixes\n\r" - + "\n【Changes】\n - Hex Master hex icon changed to separate it from Spellcaster\n - Fortune Teller moved to Experimentals due to a planned and unfinished rework\n\r" - - + "\n【New Features】\n - New role: Twister (role by papercut on Discord)\n\r - New role: Chameleon (from Project: Lotus)\n\r - New role: Morphling\n\r - New role: Inspector (role by ryuk on Discord)\n\r - New role: Medusa\n\r - New add-on: Lazy\n\r - New add-on: Gravestone\n\r - New add-on: Autopsy (from TOHY)\n\r - New add-on: Loyal\n\r - New add-on: Visionary\n\r- New experimental role: Spiritcaller (role by papercut on Discord)\n\r" - - + "\n【Role Changes】\n - Various changes were made, such as an update to Opportunist\n\r", + + "\n【Base】\n - Base on TOH v4.1.2\r\n" + + "\n【Fixes】\n - Various bug fixes\n\r" + + "\n【Changes】\n - Hex Master hex icon changed to separate it from Spellcaster\n - Fortune Teller moved to Experimentals due to a planned and unfinished rework\n\r" + + "\n【New Features】\n - New role: Twister (role by papercut on Discord)\n\r - New role: Chameleon (from Project: Lotus)\n\r - New role: Morphling\n\r - New role: Inspector (role by ryuk on Discord)\n\r - New role: Medusa\n\r - New add-on: Lazy\n\r - New add-on: Gravestone\n\r - New add-on: Autopsy (from TOHY)\n\r - New add-on: Loyal\n\r - New add-on: Visionary\n\r- New experimental role: Spiritcaller (role by papercut on Discord)\n\r" + + "\n【Role Changes】\n - Various changes were made, such as an update to Opportunist\n\r", Date = "2023-7-14T00:00:00Z" - }; AllModNews.Add(news); } @@ -77,28 +74,24 @@ public class ModNewsHistory SubTitle = "★★★★Ooooh bigger update★★★★", ShortTitle = "★TOHE v2.4.2", Text = "Added in some new stuff, along with some bug fixes.\r\nAmong Us v2023.3.28 is recommended so the roles work correctly.\n" - - + "\n【Base】\n - Base on TOH v4.1.2\r\n" - + "\n【Fixes】\n - Fixed various black screen bugs (some still exist but should be less common)\r\n - Other various bug fixes (they're hard to keep track of)\r\n" - + "\n【Changes】\n - Judge now supports Guesser Mode\r\n - Background image reverted to use the AU v2023.3.28 size due to the recommended Among Us version being v2023.3.28\r\n - Many other unlisted changes\r\n - Mario renamed to Vector due to copyright concerns\r\n" - - + "\n【New Features】\n - ###Impostors\n - Councillor\r\n - Deathpact (role by papercut on Discord)\r\n - Saboteur (25% chance to replace Inhibitor)\r\n - Consigliere (by Yumeno from TOHY)\r\n - Dazzler (role by papercut on Discord)\r\n - Devourer (role by papercut on Discord)\r\n" - + "\n ### Crewmates\n - Addict (role by papercut on Discord)\r\n - Tracefinder\r\n - Deputy\r\n - Merchant (role by papercut on Discord)\r\n - Oracle\r\n - Spiritualist (role by papercut on Discord)\r\n - Retributionist\r\n- Guardian\r\n - Monarch\r\n" - + "\n ### Neutrals\n - Maverick\r\n - Cursed Soul\r\n - Vulture (role by ryuk on Discord)\r\n - Jinx\r\n - Pickpocket\r\n - Ritualist\r\n - Traitor\r\n" - + "\n ### Add-ons\n - Double Shot (add-on by TommyXL)\r\n - Rascal\r\n" - - + "\n【Role Changes】\n - Mimic now has a setting to see the roles of dead players, due to how useless this add-on was\r\n - A revealed Workaholic can no longer be guessed\r\n - Doctor has a new setting like Workaholic to be revealed to all (currently exposes evil Doctors, use at your own risk)\r\n - Mayor has a setting for a TOS mechanic to reveal themselves\r\n - Warlock balancing\r\n - Cleaner balancing (resets kill cooldown to value set in Cleaner settings)\r\n - Updated Monarch\r\n- Removed speed boost from Mare\r\n" - + "\n【Removals】\n - Removed Flash\r\n - Removed Speed Booster\r\n - Temporarily removed Oblivious", + + "\n【Base】\n - Base on TOH v4.1.2\r\n" + + "\n【Fixes】\n - Fixed various black screen bugs (some still exist but should be less common)\r\n - Other various bug fixes (they're hard to keep track of)\r\n" + + "\n【Changes】\n - Judge now supports Guesser Mode\r\n - Background image reverted to use the AU v2023.3.28 size due to the recommended Among Us version being v2023.3.28\r\n - Many other unlisted changes\r\n - Mario renamed to Vector due to copyright concerns\r\n" + + "\n【New Features】\n - ###Impostors\n - Councillor\r\n - Deathpact (role by papercut on Discord)\r\n - Saboteur (25% chance to replace Inhibitor)\r\n - Consigliere (by Yumeno from TOHY)\r\n - Dazzler (role by papercut on Discord)\r\n - Devourer (role by papercut on Discord)\r\n" + + "\n ### Crewmates\n - Addict (role by papercut on Discord)\r\n - Tracefinder\r\n - Deputy\r\n - Merchant (role by papercut on Discord)\r\n - Oracle\r\n - Spiritualist (role by papercut on Discord)\r\n - Retributionist\r\n- Guardian\r\n - Monarch\r\n" + + "\n ### Neutrals\n - Maverick\r\n - Cursed Soul\r\n - Vulture (role by ryuk on Discord)\r\n - Jinx\r\n - Pickpocket\r\n - Ritualist\r\n - Traitor\r\n" + + "\n ### Add-ons\n - Double Shot (add-on by TommyXL)\r\n - Rascal\r\n" + + "\n【Role Changes】\n - Mimic now has a setting to see the roles of dead players, due to how useless this add-on was\r\n - A revealed Workaholic can no longer be guessed\r\n - Doctor has a new setting like Workaholic to be revealed to all (currently exposes evil Doctors, use at your own risk)\r\n - Mayor has a setting for a TOS mechanic to reveal themselves\r\n - Warlock balancing\r\n - Cleaner balancing (resets kill cooldown to value set in Cleaner settings)\r\n - Updated Monarch\r\n- Removed speed boost from Mare\r\n" + + "\n【Removals】\n - Removed Flash\r\n - Removed Speed Booster\r\n - Temporarily removed Oblivious", Date = "2023-7-5T00:00:00Z" - }; AllModNews.Add(news); } } [HarmonyPatch(typeof(PlayerAnnouncementData), nameof(PlayerAnnouncementData.SetAnnouncements)), HarmonyPrefix] - public static bool SetModAnnouncements(/*PlayerAnnouncementData __instance,*/ [HarmonyArgument(0)] ref Il2CppReferenceArray aRange) + public static bool SetModAnnouncements( /*PlayerAnnouncementData __instance,*/ [HarmonyArgument(0)] ref Il2CppReferenceArray aRange) { if (AllModNews.Count == 0) { @@ -113,6 +106,7 @@ public class ModNewsHistory if (!AllModNews.Any(x => x.Number == news.Number)) FinalAllNews.Add(news); } + FinalAllNews.Sort((a1, a2) => { return DateTime.Compare(DateTime.Parse(a2.Date), DateTime.Parse(a1.Date)); }); aRange = new(FinalAllNews.Count); diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index b34f5aca6..602755c24 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -1,3 +1,6 @@ +using Assets.CoreScripts; +using HarmonyLib; +using Hazel; using System; using System.Collections; using System.Collections.Generic; @@ -5,9 +8,6 @@ using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; -using Assets.CoreScripts; -using HarmonyLib; -using Hazel; using TOHE.Modules; using TOHE.Roles.Crewmate; using TOHE.Roles.Impostor; @@ -557,7 +557,6 @@ internal class ChatCommands if (!rl.IsAdditionRole()) { HudManager.Instance.SetHudActive(pc, pc.Data.Role, !GameStates.IsMeeting); - Utils.AddRoles(pc.PlayerId, rl); } Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.NotAssigned); diff --git a/Patches/ChatControlPatch.cs b/Patches/ChatControlPatch.cs index 9bc128d04..7bcbe75aa 100644 --- a/Patches/ChatControlPatch.cs +++ b/Patches/ChatControlPatch.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; using AmongUs.Data; using HarmonyLib; using InnerNet; +using System; +using System.Collections.Generic; +using System.Linq; using TOHE.Roles.Impostor; using UnityEngine; @@ -13,11 +13,13 @@ namespace TOHE; class ChatControllerUpdatePatch { public static int CurrentHistorySelection = -1; + public static void Prefix() { if (AmongUsClient.Instance.AmHost && DataManager.Settings.Multiplayer.ChatMode == QuickChatModes.QuickChatOnly) DataManager.Settings.Multiplayer.ChatMode = QuickChatModes.FreeChatOrQuickChat; //コマンドを打つためにホストのみ常時フリーチャット開放 } + public static void Postfix(ChatController __instance) { if (!__instance.freeChatField.textArea.hasFocus) return; @@ -32,11 +34,13 @@ class ChatControllerUpdatePatch ClipboardHelper.PutClipboardString(__instance.freeChatField.textArea.text); __instance.freeChatField.textArea.SetText(""); } + if (Input.GetKeyDown(KeyCode.UpArrow) && ChatCommands.ChatHistory.Count > 0) { CurrentHistorySelection = Mathf.Clamp(--CurrentHistorySelection, 0, ChatCommands.ChatHistory.Count - 1); __instance.freeChatField.textArea.SetText(ChatCommands.ChatHistory[CurrentHistorySelection]); } + if (Input.GetKeyDown(KeyCode.DownArrow) && ChatCommands.ChatHistory.Count > 0) { CurrentHistorySelection++; @@ -52,10 +56,12 @@ public static class ChatManager public static bool cancel; private static readonly List chatHistory = []; private const int maxHistorySize = 20; + public static void ResetHistory() { chatHistory.Clear(); } + public static bool CheckCommand(ref string msg, string command, bool exact = true) { var comList = command.Split('|'); @@ -74,8 +80,10 @@ public static class ChatManager } } } + return false; } + public static bool CheckName(ref string msg, string command, bool exact = true) { var comList = command.Split('|'); @@ -98,8 +106,10 @@ public static class ChatManager } } } + return false; } + public static void SendMessage(PlayerControl player, string message) { int operate; @@ -194,6 +204,7 @@ public static class ChatManager ChatUpdatePatch.DoBlockChat = false; } + private static void SendRPC(PlayerControl senderPlayer, string senderMessage) { var writer = CustomRpcSender.Create("MessagesToSend"); diff --git a/Patches/ControlPatch.cs b/Patches/ControlPatch.cs index dee5a61fa..c2e6e2f65 100644 --- a/Patches/ControlPatch.cs +++ b/Patches/ControlPatch.cs @@ -1,9 +1,9 @@ +using HarmonyLib; +using Rewired; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using HarmonyLib; -using Rewired; using UnityEngine; using static TOHE.Translator; @@ -18,7 +18,7 @@ internal class ControllerManagerUpdatePatch public static List addDes = []; public static int addonIndex = -1; - public static void Postfix(/*ControllerManager __instance*/) + public static void Postfix( /*ControllerManager __instance*/) { //切换自定义设置的页面 if (GameStates.IsLobby) @@ -27,17 +27,20 @@ internal class ControllerManagerUpdatePatch { OptionShower.Next(); } + for (var i = 0; i < 9; i++) { if (ORGetKeysDown(KeyCode.Alpha1 + i, KeyCode.Keypad1 + i) && OptionShower.pages.Count >= i + 1) OptionShower.currentPage = i; } } + //捕捉全屏快捷键 if (GetKeysDown(KeyCode.LeftAlt, KeyCode.Return)) { _ = new LateTask(SetResolutionManager.Postfix, 0.01f, "Fix Button Position"); } + //职业介绍 if (Input.GetKeyDown(KeyCode.F1) && GameStates.InGame && Options.CurrentGameMode == CustomGameMode.Standard) { @@ -57,6 +60,7 @@ internal class ControllerManagerUpdatePatch throw; } } + //附加职业介绍 if (Input.GetKeyDown(KeyCode.F2) && GameStates.InGame && Options.CurrentGameMode == CustomGameMode.Standard) { @@ -80,6 +84,7 @@ internal class ControllerManagerUpdatePatch throw; } } + //更改分辨率 if (Input.GetKeyDown(KeyCode.F11)) { @@ -88,6 +93,7 @@ internal class ControllerManagerUpdatePatch ResolutionManager.SetResolution(resolutions[resolutionIndex].Item1, resolutions[resolutionIndex].Item2, false); SetResolutionManager.Postfix(); } + //重新加载自定义翻译 if (GetKeysDown(KeyCode.F5, KeyCode.T)) { @@ -95,18 +101,21 @@ internal class ControllerManagerUpdatePatch LoadLangs(); Logger.SendInGame("Reloaded Custom Translation File"); } + if (GetKeysDown(KeyCode.F5, KeyCode.X)) { Logger.Info("导出自定义翻译文件", "KeyCommand"); ExportCustomTranslation(); Logger.SendInGame("Exported Custom Translation File"); } + //日志文件转储 if (GetKeysDown(KeyCode.F1, KeyCode.LeftControl)) { Logger.Info("输出日志", "KeyCommand"); Utils.DumpLog(); } + //将当前设置复制为文本 if (GetKeysDown(KeyCode.LeftAlt, KeyCode.C) && !Input.GetKey(KeyCode.LeftShift) && !GameStates.IsNotJoined) { @@ -125,18 +134,21 @@ internal class ControllerManagerUpdatePatch { HudManager.Instance.Chat.SetVisible(true); } + //强制结束游戏 if (GetKeysDown(KeyCode.Return, KeyCode.L, KeyCode.LeftShift) && GameStates.IsInGame) { CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Draw); GameManager.Instance.LogicFlow.CheckEndCriteria(); } + //强制结束会议或召开会议 if (GetKeysDown(KeyCode.Return, KeyCode.M, KeyCode.LeftShift) && GameStates.IsInGame) { if (GameStates.IsMeeting) MeetingHud.Instance.RpcClose(); else PlayerControl.LocalPlayer.NoCheckStartMeeting(null, true); } + //立即开始 if (Input.GetKeyDown(KeyCode.LeftShift) && GameStates.IsCountDown && !HudManager.Instance.Chat.IsOpenOrOpening) { @@ -151,18 +163,21 @@ internal class ControllerManagerUpdatePatch GameStartManager.Instance.ResetStartState(); Logger.SendInGame(GetString("CancelStartCountDown")); } + //显示当前有效设置的说明 if (GetKeysDown(KeyCode.N, KeyCode.LeftShift, KeyCode.LeftControl)) { Main.isChatCommand = true; Utils.ShowActiveSettingsHelp(); } + //显示当前有效设置 if (GetKeysDown(KeyCode.N, KeyCode.LeftControl) && !Input.GetKey(KeyCode.LeftShift)) { Main.isChatCommand = true; Utils.ShowActiveSettings(); } + //将 TOHE 选项设置为默认值 //if (GetKeysDown(KeyCode.Delete, KeyCode.LeftControl)) //{ @@ -184,6 +199,7 @@ internal class ControllerManagerUpdatePatch Main.PlayerStates[PlayerControl.LocalPlayer.PlayerId].SetDead(); Utils.SendMessage(GetString("HostKillSelfByCommand"), title: $"{GetString("DefaultSystemMessageTitle")}"); } + //切换日志是否也在游戏中输出 if (GetKeysDown(KeyCode.F2, KeyCode.LeftControl)) { @@ -249,6 +265,7 @@ internal class ControllerManagerUpdatePatch HudManager.Instance.StartCoroutine(HudManager.Instance.CoFadeFullScreen(Color.clear, Color.black)); HudManager.Instance.StartCoroutine(DestroyableSingleton.Instance.CoShowIntro()); } + //任务数显示切换 if (Input.GetKeyDown(KeyCode.Equals)) { @@ -268,6 +285,7 @@ internal class ControllerManagerUpdatePatch if (!pc.AmOwner) pc.MyPhysics.RpcEnterVent(2); } } + if (Input.GetKeyDown(KeyCode.V)) { Vector2 pos = PlayerControl.LocalPlayer.NetTransform.transform.position; @@ -280,6 +298,7 @@ internal class ControllerManagerUpdatePatch } } } + if (Input.GetKeyDown(KeyCode.B)) { foreach (var pc in PlayerControl.AllPlayerControls) @@ -287,6 +306,7 @@ internal class ControllerManagerUpdatePatch if (!pc.AmOwner) pc.MyPhysics.RpcExitVent(2); } } + if (Input.GetKeyDown(KeyCode.N)) { VentilationSystem.Update(VentilationSystem.Operation.StartCleaning, 0); @@ -301,6 +321,7 @@ internal class ControllerManagerUpdatePatch Logger.Info($"Shortcut Key:{keys.Where(Input.GetKeyDown).First()} in [{string.Join(",", keys)}]", "GetKeysDown"); return true; } + return false; } @@ -315,6 +336,7 @@ internal class ConsoleJoystickHandleHUDPatch HandleHUDPatch.Postfix(ConsoleJoystick.player); } } + [HarmonyPatch(typeof(KeyboardJoystick), nameof(KeyboardJoystick.HandleHud))] internal class KeyboardJoystickHandleHUDPatch { @@ -329,14 +351,15 @@ internal class HandleHUDPatch public static void Postfix(Player player) { if (player.GetButtonDown(8) && // 8:キルボタンのactionId - PlayerControl.LocalPlayer.Data?.Role?.IsImpostor == false && - PlayerControl.LocalPlayer.CanUseKillButton()) + PlayerControl.LocalPlayer.Data?.Role?.IsImpostor == false && + PlayerControl.LocalPlayer.CanUseKillButton()) { DestroyableSingleton.Instance.KillButton.DoClick(); } + if (player.GetButtonDown(50) && // 50:インポスターのベントボタンのactionId - PlayerControl.LocalPlayer.Data?.Role?.IsImpostor == false && - PlayerControl.LocalPlayer.CanUseImpostorVentButton()) + PlayerControl.LocalPlayer.Data?.Role?.IsImpostor == false && + PlayerControl.LocalPlayer.CanUseImpostorVentButton()) { DestroyableSingleton.Instance.ImpostorVentButton.DoClick(); } diff --git a/Patches/CredentialsPatch.cs b/Patches/CredentialsPatch.cs index 19b5eb93d..2f877d1b9 100644 --- a/Patches/CredentialsPatch.cs +++ b/Patches/CredentialsPatch.cs @@ -1,7 +1,7 @@ +using HarmonyLib; using System; using System.Linq; using System.Text; -using HarmonyLib; using TMPro; using TOHE.Modules; using UnityEngine; @@ -16,6 +16,7 @@ internal class PingTrackerUpdatePatch private static readonly StringBuilder sb = new(); private static long LastUpdate; private static int Delay => GameStates.IsInTask ? 8 : 1; + private static void Postfix(PingTracker __instance) { __instance.text.alignment = TextAlignmentOptions.TopRight; @@ -50,6 +51,7 @@ internal class PingTrackerUpdatePatch __instance.GetComponent().DistanceFromEdge = new Vector3(offset_x, 0f, 0f); } } + [HarmonyPatch(typeof(VersionShower), nameof(VersionShower.Start))] internal class VersionShowerStartPatch { @@ -122,6 +124,7 @@ internal class TitleLogoPatch LoadingHintText.fontSize = 5f; __instance.playButton.transform.gameObject.SetActive(false); } + if ((Ambience = GameObject.Find("Ambience")) != null) { try @@ -197,6 +200,7 @@ internal class TitleLogoPatch __instance.screenTint.gameObject.transform.localPosition += new Vector3(1000f, 0f); __instance.screenTint.enabled = false; } + __instance.rightPanelMask?.SetActive(true); GameObject leftPanel = GameObject.Find("LeftPanel")?.transform.gameObject; @@ -227,6 +231,7 @@ internal class TitleLogoPatch } } } + [HarmonyPatch(typeof(ModManager), nameof(ModManager.LateUpdate))] internal class ModManagerLateUpdatePatch { @@ -237,6 +242,7 @@ internal class ModManagerLateUpdatePatch LateTask.Update(Time.deltaTime); CheckMurderPatch.Update(); } + public static void Postfix(ModManager __instance) { var offset_y = HudManager.InstanceExists ? 1.6f : 0.9f; diff --git a/Patches/DiscordPatch.cs b/Patches/DiscordPatch.cs index a35e295fd..52b38035d 100644 --- a/Patches/DiscordPatch.cs +++ b/Patches/DiscordPatch.cs @@ -1,7 +1,7 @@ -using System; using AmongUs.Data; using Discord; using HarmonyLib; +using System; namespace TOHE.Patches { @@ -11,6 +11,7 @@ namespace TOHE.Patches { private static string lobbycode = ""; private static string region = ""; + public static void Prefix([HarmonyArgument(0)] Activity activity) { var details = $"TOHE+ v{Main.PluginDisplayVersion}"; @@ -61,4 +62,4 @@ namespace TOHE.Patches } } } -} +} \ No newline at end of file diff --git a/Patches/ExilePatch.cs b/Patches/ExilePatch.cs index 1adf067c0..1eaac6bb7 100644 --- a/Patches/ExilePatch.cs +++ b/Patches/ExilePatch.cs @@ -1,7 +1,7 @@ -using System.Linq; using AmongUs.Data; using AmongUs.GameOptions; using HarmonyLib; +using System.Linq; using TOHE.Roles.AddOns.Crewmate; using TOHE.Roles.AddOns.Impostor; using TOHE.Roles.Crewmate; diff --git a/Patches/GameOptionsMenuPatch.cs b/Patches/GameOptionsMenuPatch.cs index b0c1872ad..2a27d00aa 100644 --- a/Patches/GameOptionsMenuPatch.cs +++ b/Patches/GameOptionsMenuPatch.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections; -using System.Linq; using AmongUs.GameOptions; using HarmonyLib; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppSystem.Collections.Generic; +using System; +using System.Collections; +using System.Linq; using TMPro; using UnityEngine; using UnityEngine.UI; diff --git a/Patches/GameStartManagerPatch.cs b/Patches/GameStartManagerPatch.cs index 71fc01214..43cbd93e5 100644 --- a/Patches/GameStartManagerPatch.cs +++ b/Patches/GameStartManagerPatch.cs @@ -1,10 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; using AmongUs.Data; using AmongUs.GameOptions; using HarmonyLib; using InnerNet; +using System; +using System.Collections.Generic; +using System.Linq; using TMPro; using TOHE.Roles.Neutral; using UnityEngine; @@ -18,18 +18,28 @@ public static class GameStartManagerUpdatePatch { public static void Prefix(GameStartManager __instance) { - try { __instance.MinPlayers = 1; } catch (Exception ex) { Logger.Error(ex.ToString(), "Surely this can't be causing an issue, right?"); } + try + { + __instance.MinPlayers = 1; + } + catch (Exception ex) + { + Logger.Error(ex.ToString(), "Surely this can't be causing an issue, right?"); + } } } + //タイマーとコード隠し public class GameStartManagerPatch { private static SpriteRenderer cancelButton; private static float timer = 600f; + [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.Start))] public class GameStartManagerStartPatch { public static TextMeshPro HideName; + public static void Postfix(GameStartManager __instance) { try @@ -42,8 +52,8 @@ public class GameStartManagerPatch HideName = Object.Instantiate(__instance.GameRoomNameCode, __instance.GameRoomNameCode.transform); HideName.text = ColorUtility.TryParseHtmlString(Main.HideColor.Value, out _) - ? $"{Main.HideName.Value}" - : $"{Main.HideName.Value}"; + ? $"{Main.HideName.Value}" + : $"{Main.HideName.Value}"; cancelButton = Object.Instantiate(__instance.StartButton, __instance.transform); cancelButton.name = "CancelButton"; @@ -92,6 +102,7 @@ public class GameStartManagerPatch public static float exitTimer = -1f; private static float minWait, maxWait; private static int minPlayer; + public static void Prefix(GameStartManager __instance) { try @@ -147,10 +158,12 @@ public class GameStartManagerPatch msg += "\n" + string.Join(",", invalidColor.Select(p => $"{p.GetRealName()}")); Utils.SendMessage(msg); } + if (Options.RandomMapsMode.GetBool()) { Main.NormalOptions.MapId = GameStartRandomMap.SelectRandomMap(); } + GameStartManager.Instance.startState = GameStartManager.StartingStates.Countdown; GameStartManager.Instance.countDownTimer = Options.AutoStartTimer.GetInt(); __instance.StartButton.gameObject.SetActive(false); @@ -158,12 +171,15 @@ public class GameStartManagerPatch } } } - catch (NullReferenceException) { } + catch (NullReferenceException) + { + } catch (Exception ex) { Logger.Error(ex.ToString(), "GameStartManagerUpdatePatch.Prefix (2)"); } } + public static void Postfix(GameStartManager __instance) { try @@ -187,11 +203,13 @@ public class GameStartManagerPatch mismatchedPlayerNameList.Add(Utils.ColorString(Palette.PlayerColors[client.ColorId], client.Character.Data.PlayerName)); } } + if (!canStartGame) { __instance.StartButton.gameObject.SetActive(false); warningMessage = Utils.ColorString(Color.red, string.Format(GetString("Warning.MismatchedVersion"), string.Join(" ", mismatchedPlayerNameList), $"{Main.ModName}")); } + cancelButton.gameObject.SetActive(__instance.startState == GameStartManager.StartingStates.Countdown); } else @@ -207,10 +225,12 @@ public class GameStartManagerPatch AmongUsClient.Instance.ExitGame(DisconnectReasons.ExitGame); SceneChanger.ChangeScene("MainMenu"); } + if (exitTimer != 0) warningMessage = Utils.ColorString(Color.red, string.Format(GetString("Warning.AutoExitAtMismatchedVersion"), $"{Main.ModName}", Math.Round(5 - exitTimer).ToString())); } } + if (warningMessage != "") { __instance.GameStartText.text = warningMessage; @@ -235,20 +255,24 @@ public class GameStartManagerPatch __instance.PlayerCounter.text = currentText + suffix; __instance.PlayerCounter.autoSizeTextContainer = true; } - catch (NullReferenceException) { } + catch (NullReferenceException) + { + } catch (Exception e) { Logger.Error(e.ToString(), "GameStartManagerUpdatePatch.Postfix (3)"); } } + private static bool MatchVersions(byte playerId, bool acceptVanilla = false) { if (!Main.playerVersion.TryGetValue(playerId, out var version)) return acceptVanilla; return Main.ForkId == version.forkId - && Main.version.CompareTo(version.version) == 0 - && version.tag == $"{ThisAssembly.Git.Commit}({ThisAssembly.Git.Branch})"; + && Main.version.CompareTo(version.version) == 0 + && version.tag == $"{ThisAssembly.Git.Commit}({ThisAssembly.Git.Branch})"; } } + [HarmonyPatch(typeof(TextBoxTMP), nameof(TextBoxTMP.SetText))] public static class HiddenTextPatch { @@ -258,6 +282,7 @@ public class GameStartManagerPatch } } } + [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.BeginGame))] public class GameStartRandomMap { @@ -288,15 +313,18 @@ public class GameStartRandomMap __instance.ReallyBegin(false); return false; } - public static bool Prefix(/*GameStartRandomMap __instance*/) + + public static bool Prefix( /*GameStartRandomMap __instance*/) { bool continueStart = true; if (Options.RandomMapsMode.GetBool()) { Main.NormalOptions.MapId = SelectRandomMap(); } + return continueStart; } + public static byte SelectRandomMap() { var rand = IRandom.Instance; @@ -334,6 +362,7 @@ public class GameStartRandomMap } } } + [HarmonyPatch(typeof(GameStartManager), nameof(GameStartManager.ResetStartState))] class ResetStartStatePatch { @@ -346,6 +375,7 @@ class ResetStartStatePatch } } } + [HarmonyPatch(typeof(IGameOptionsExtensions), nameof(IGameOptionsExtensions.GetAdjustedNumImpostors))] class UnrestrictedNumImpostorsPatch { diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 43a20a846..c4275cd2d 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using HarmonyLib; @@ -10,8 +11,9 @@ using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; using UnityEngine; using static TOHE.Translator; +using Object = UnityEngine.Object; -namespace TOHE; +namespace TOHE.Patches; [HarmonyPatch(typeof(HudManager), nameof(HudManager.Update))] class HudManagerPatch @@ -46,7 +48,7 @@ class HudManagerPatch } } - if (player.Collider.offset.y == 127f) + if (Math.Abs(player.Collider.offset.y - 127f) < 0.1f) { if (!Input.GetKey(KeyCode.LeftControl) || (AmongUsClient.Instance.IsGameStarted && GameStates.IsOnlineGame)) { @@ -93,9 +95,8 @@ class HudManagerPatch if (Main.SetRoles.Count == 0) first = true; foreach (var item in Main.SetAddOns) { - for (int i = 0; i < item.Value.Count; i++) + foreach (var role in item.Value) { - CustomRoles role = item.Value[i]; var pc = Utils.GetPlayerById(item.Key); if (resultText.ContainsKey(item.Key)) { @@ -156,17 +157,12 @@ class HudManagerPatch { if (player.IsAlive() || Options.CurrentGameMode is CustomGameMode.FFA or CustomGameMode.MoveAndStop or CustomGameMode.HotPotato) { - //MOD入り用のボタン下テキスト変更 + Main.PlayerStates[player.PlayerId].Role.SetButtonTexts(__instance, player.PlayerId); + switch (player.GetCustomRole()) { - case CustomRoles.Sniper: - Sniper.OverrideShapeText(player.PlayerId); - break; case CustomRoles.FireWorks: - if (FireWorks.nowFireWorksCount[player.PlayerId] == 0) - __instance.AbilityButton?.OverrideText(GetString("FireWorksExplosionButtonText")); - else - __instance.AbilityButton?.OverrideText(GetString("FireWorksInstallAtionButtonText")); + __instance.AbilityButton?.OverrideText((Main.PlayerStates[player.PlayerId].Role as FireWorks).nowFireWorksCount == 0 ? GetString("FireWorksExplosionButtonText") : GetString("FireWorksInstallAtionButtonText")); break; //case CustomRoles.SerialKiller: // SerialKiller.GetAbilityButtonText(__instance, player); @@ -181,15 +177,6 @@ class HudManagerPatch case CustomRoles.Witch: Witch.GetAbilityButtonText(__instance); break; - case CustomRoles.HexMaster: - HexMaster.GetAbilityButtonText(__instance); - break; - case CustomRoles.Vampire: - Vampire.SetKillButtonText(); - break; - case CustomRoles.Poisoner: - Poisoner.SetKillButtonText(); - break; case CustomRoles.Arsonist: __instance.KillButton?.OverrideText(GetString("ArsonistDouseButtonText")); __instance.ImpostorVentButton.buttonLabelText.text = GetString("ArsonistVentButtonText"); @@ -203,9 +190,6 @@ class HudManagerPatch //case CustomRoles.BountyHunter: // BountyHunter.SetAbilityButtonText(__instance); // break; - case CustomRoles.EvilTracker: - EvilTracker.GetAbilityButtonText(__instance, player.PlayerId); - break; case CustomRoles.Capitalism: __instance.KillButton?.OverrideText(GetString("CapitalismButtonText")); break; @@ -221,40 +205,6 @@ class HudManagerPatch case CustomRoles.Pursuer: __instance.KillButton?.OverrideText(GetString("PursuerButtonText")); break; - case CustomRoles.Gangster: - Gangster.SetKillButtonText(player.PlayerId); - break; - case CustomRoles.NSerialKiller: - case CustomRoles.SoulHunter: - case CustomRoles.Enderman: - case CustomRoles.Mycologist: - case CustomRoles.Bubble: - case CustomRoles.Hookshot: - case CustomRoles.Sprayer: - case CustomRoles.Magician: - case CustomRoles.WeaponMaster: - case CustomRoles.Reckless: - case CustomRoles.Pyromaniac: - case CustomRoles.Eclipse: - case CustomRoles.Vengeance: - case CustomRoles.HeadHunter: - case CustomRoles.Imitator: - case CustomRoles.Werewolf: - case CustomRoles.RuthlessRomantic: - case CustomRoles.Juggernaut: - case CustomRoles.Jackal: - case CustomRoles.Virus: - case CustomRoles.BloodKnight: - case CustomRoles.SwordsMan: - case CustomRoles.Parasite: - case CustomRoles.Refugee: - case CustomRoles.Traitor: - case CustomRoles.Ritualist: - case CustomRoles.Spiritcaller: - case CustomRoles.DarkHide: - case CustomRoles.Maverick: - __instance.KillButton?.OverrideText(GetString("KillButtonText")); - break; case CustomRoles.Postman: __instance.KillButton?.OverrideText(GetString("PostmanKillButtonText")); break; @@ -316,17 +266,6 @@ class HudManagerPatch case CustomRoles.OverKiller: __instance.KillButton?.OverrideText(GetString("OverKillerButtonText")); break; - case CustomRoles.Assassin: - Assassin.SetKillButtonText(player.PlayerId); - Assassin.GetAbilityButtonText(__instance, player.PlayerId); - break; - case CustomRoles.Undertaker: - Undertaker.SetKillButtonText(player.PlayerId); - Undertaker.GetAbilityButtonText(__instance, player.PlayerId); - break; - case CustomRoles.Hacker: - Hacker.GetAbilityButtonText(__instance, player.PlayerId); - break; case CustomRoles.KB_Normal: __instance.KillButton?.OverrideText(GetString("GamerButtonText")); break; @@ -348,18 +287,6 @@ class HudManagerPatch __instance.AbilityButton?.SetUsesRemaining((int)player.GetAbilityUseLimit()); } - break; - case CustomRoles.Swooper: - __instance.ImpostorVentButton?.OverrideText(GetString(Swooper.IsInvis(PlayerControl.LocalPlayer.PlayerId) ? "SwooperRevertVentButtonText" : "SwooperVentButtonText")); - __instance.ImpostorVentButton?.OverrideText(GetString(Swooper.CanGoInvis(PlayerControl.LocalPlayer.PlayerId) ? "SwooperVentButtonText" : "VentButtonText")); - break; - case CustomRoles.Wraith: - __instance.KillButton?.OverrideText(GetString("KillButtonText")); - __instance.ImpostorVentButton?.OverrideText(GetString(Wraith.IsInvis(PlayerControl.LocalPlayer.PlayerId) ? "WraithRevertVentButtonText" : "WraithVentButtonText")); - __instance.ImpostorVentButton?.OverrideText(GetString(Swooper.CanGoInvis(PlayerControl.LocalPlayer.PlayerId) ? "WraithVentButtonText" : "VentButtonText")); - break; - case CustomRoles.Chameleon: - __instance.AbilityButton?.OverrideText(GetString(Chameleon.IsInvis(PlayerControl.LocalPlayer.PlayerId) ? "ChameleonRevertDisguise" : "ChameleonDisguise")); break; case CustomRoles.Sheriff: __instance.KillButton?.OverrideText(GetString("SheriffKillButtonText")); @@ -377,11 +304,6 @@ class HudManagerPatch case CustomRoles.VengefulRomantic: __instance.KillButton?.OverrideText(GetString("VengefulRomanticKillButtonText")); break; - case CustomRoles.Penguin: - __instance.KillButton?.OverrideText(Penguin.OverrideKillButtonText()); - __instance.AbilityButton?.OverrideText(Penguin.GetAbilityButtonText()); - __instance.AbilityButton?.ToggleVisible(Penguin.CanUseAbilityButton()); - break; case CustomRoles.Succubus: __instance.KillButton?.OverrideText(GetString("SuccubusKillButtonText")); break; @@ -452,24 +374,20 @@ class HudManagerPatch CustomGameMode.Standard => player.GetCustomRole() switch { CustomRoles.BountyHunter => BountyHunter.GetTargetText(player, true), - CustomRoles.Witch => Witch.GetSpellModeText(player, true), - CustomRoles.HexMaster => HexMaster.GetHexModeText(player, true), + CustomRoles.Witch or CustomRoles.HexMaster => Witch.GetSpellModeText(player, true), CustomRoles.FireWorks => FireWorks.GetStateText(player), - CustomRoles.Swooper => Swooper.GetHudText(player), - CustomRoles.Wraith => Wraith.GetHudText(player), + CustomRoles.Swooper or CustomRoles.Wraith or CustomRoles.Chameleon => Swooper.GetHudText(player), CustomRoles.HeadHunter => HeadHunter.GetHudText(player), CustomRoles.Alchemist => Alchemist.GetHudText(player), - CustomRoles.Chameleon => Chameleon.GetHudText(player), CustomRoles.Werewolf => Werewolf.GetHudText(player), - CustomRoles.BloodKnight => BloodKnight.GetHudText(player), CustomRoles.Glitch => Glitch.GetHudText(player), CustomRoles.NiceHacker => NiceHacker.GetHudText(player), - CustomRoles.Wildling => Wildling.GetHudText(player), - CustomRoles.YinYanger => YinYanger.ModeText, - CustomRoles.WeaponMaster => WeaponMaster.GetHudAndProgressText(), + CustomRoles.Wildling or CustomRoles.BloodKnight => Wildling.GetHudText(player), + CustomRoles.YinYanger => YinYanger.ModeText(player), + CustomRoles.WeaponMaster => WeaponMaster.GetHudAndProgressText(player.PlayerId), CustomRoles.Postman => Postman.GetHudText(player), - CustomRoles.SoulHunter => SoulHunter.HUDText, - CustomRoles.Chronomancer => Chronomancer.GetHudText(), + CustomRoles.SoulHunter => SoulHunter.HUDText(player.PlayerId), + CustomRoles.Chronomancer => Chronomancer.GetHudText(player.PlayerId), CustomRoles.Mafioso => Mafioso.GetHUDText(player), CustomRoles.Druid => Druid.GetHUDText(player), CustomRoles.Rabbit => Rabbit.GetSuffix(player), @@ -659,18 +577,6 @@ class SetHudActivePatch case CustomRoles.Refugee: __instance.SabotageButton?.ToggleVisible(true); break; - case CustomRoles.Jackal: - Jackal.SetHudActive(__instance, isActive); - break; - case CustomRoles.Sidekick: - Sidekick.SetHudActive(__instance, isActive); - break; - case CustomRoles.Traitor: - Traitor.SetHudActive(__instance, isActive); - break; - case CustomRoles.Glitch: - Glitch.SetHudActive(__instance); - break; case CustomRoles.Magician: __instance.SabotageButton?.ToggleVisible(true); break; @@ -715,7 +621,7 @@ class MapBehaviourShowPatch } else if (opts.Mode is MapOptions.Modes.Normal or MapOptions.Modes.Sabotage) { - if (player.Is(CustomRoleTypes.Impostor) || player.CanUseSabotage() || player.Is(CustomRoles.Glitch) || player.Is(CustomRoles.WeaponMaster) || player.Is(CustomRoles.Magician) || player.Is(CustomRoles.Parasite) || player.Is(CustomRoles.Refugee) || (player.Is(CustomRoles.Jackal) && Jackal.CanUseSabotage.GetBool()) || (player.Is(CustomRoles.Traitor) && Traitor.CanUseSabotage.GetBool())) + if (player.Is(CustomRoleTypes.Impostor) || player.CanUseSabotage() || player.Is(CustomRoles.Glitch) || player.Is(CustomRoles.WeaponMaster) || player.Is(CustomRoles.Magician) || player.Is(CustomRoles.Parasite) || player.Is(CustomRoles.Refugee) || (player.Is(CustomRoles.Jackal) && Jackal.CanSabotage.GetBool()) || (player.Is(CustomRoles.Traitor) && Traitor.CanSabotage.GetBool())) opts.Mode = MapOptions.Modes.Sabotage; else opts.Mode = MapOptions.Modes.Normal; @@ -796,7 +702,7 @@ class TaskPanelBehaviourPatch List<(int, byte)> list = []; foreach (var id in Main.PlayerStates.Keys) list.Add((SoloKombatManager.GetRankOfScore(id), id)); list.Sort(); - foreach (var id in list.Where(x => SummaryText.ContainsKey(x.Item2))) AllText += "\r\n" + SummaryText[id.Item2]; + AllText = list.Where(x => SummaryText.ContainsKey(x.Item2)).Aggregate(AllText, (current, id) => current + ("\r\n" + SummaryText[id.Item2])); AllText = $"{AllText}"; @@ -816,7 +722,7 @@ class TaskPanelBehaviourPatch List<(int, byte)> list2 = []; foreach (var id in Main.PlayerStates.Keys) list2.Add((FFAManager.GetRankOfScore(id), id)); list2.Sort(); - foreach (var id in list2.Where(x => SummaryText2.ContainsKey(x.Item2))) AllText += "\r\n" + SummaryText2[id.Item2]; + AllText = list2.Where(x => SummaryText2.ContainsKey(x.Item2)).Aggregate(AllText, (current, id) => current + ("\r\n" + SummaryText2[id.Item2])); AllText = $"{AllText}"; @@ -865,14 +771,7 @@ class TaskPanelBehaviourPatch case CustomGameMode.HotPotato: List SummaryText4 = []; - foreach (var id in Main.PlayerStates.Keys.ToArray()) - { - PlayerControl pc = Utils.GetPlayerById(id); - string name = pc.GetRealName().RemoveHtmlTags().Replace("\r\n", string.Empty); - bool alive = pc.IsAlive(); - string summary = $"{(!alive ? "<#777777>" : "")}{HotPotatoManager.GetIndicator(id)}{Utils.ColorString(Main.PlayerColors[id], name)}{(!alive ? " <#ff0000>DEAD" : "")}"; - SummaryText4.Add(summary); - } + SummaryText4.AddRange(from id in Main.PlayerStates.Keys.ToArray() let pc = Utils.GetPlayerById(id) let name = pc.GetRealName().RemoveHtmlTags().Replace("\r\n", string.Empty) let alive = pc.IsAlive() select $"{(!alive ? "<#777777>" : "")}{HotPotatoManager.GetIndicator(id)}{Utils.ColorString(Main.PlayerColors[id], name)}{(!alive ? " <#ff0000>DEAD" : "")}"); AllText += $"\r\n\r\n{string.Join('\n', SummaryText4)}"; diff --git a/Patches/HudSpritePatch.cs b/Patches/HudSpritePatch.cs index b72049141..8e418dcd0 100644 --- a/Patches/HudSpritePatch.cs +++ b/Patches/HudSpritePatch.cs @@ -1,4 +1,5 @@ using HarmonyLib; +using TOHE.Patches; using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; using UnityEngine; diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs index f6f5737aa..83b0a319b 100644 --- a/Patches/IntroPatch.cs +++ b/Patches/IntroPatch.cs @@ -1,9 +1,9 @@ -using System; -using System.Linq; -using System.Threading.Tasks; using AmongUs.GameOptions; using HarmonyLib; using Il2CppSystem.Collections.Generic; +using System; +using System.Linq; +using System.Threading.Tasks; using UnityEngine; using static TOHE.Translator; diff --git a/Patches/JoinGameButtonPatch.cs b/Patches/JoinGameButtonPatch.cs index b5915ac29..a3896aace 100644 --- a/Patches/JoinGameButtonPatch.cs +++ b/Patches/JoinGameButtonPatch.cs @@ -1,5 +1,5 @@ -using System.Text.RegularExpressions; using HarmonyLib; +using System.Text.RegularExpressions; using UnityEngine; namespace TOHE; diff --git a/Patches/LadderPatch.cs b/Patches/LadderPatch.cs index 3401da7bb..4734a806a 100644 --- a/Patches/LadderPatch.cs +++ b/Patches/LadderPatch.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; -using HarmonyLib; +using HarmonyLib; using Hazel; +using System.Collections.Generic; using UnityEngine; namespace TOHE; @@ -9,10 +9,12 @@ public class FallFromLadder { public static Dictionary TargetLadderData; private static int Chance => (Options.LadderDeathChance as StringOptionItem).GetChance(); + public static void Reset() { TargetLadderData = []; } + public static void OnClimbLadder(PlayerPhysics player, Ladder source) { if (!Options.LadderDeath.GetBool()) return; @@ -28,6 +30,7 @@ public class FallFromLadder } } } + public static void FixedUpdate(PlayerControl player) { if (player.Data.Disconnected) return; @@ -43,12 +46,12 @@ public class FallFromLadder ushort num2 = (ushort)(NetHelpers.YRange.ReverseLerp(targetPos.y) * 65535f); CustomRpcSender sender = CustomRpcSender.Create("LadderFallRpc", sendOption: SendOption.None); sender.AutoStartRpc(player.NetTransform.NetId, (byte)RpcCalls.SnapTo) - .Write(num) - .Write(num2) + .Write(num) + .Write(num2) .EndRpc(); sender.AutoStartRpc(player.NetId, (byte)RpcCalls.MurderPlayer) - .WriteNetObject(player) - .Write((byte)ExtendedPlayerControl.ResultFlags) + .WriteNetObject(player) + .Write((byte)ExtendedPlayerControl.ResultFlags) .EndRpc(); sender.SendMessage(); player.NetTransform.SnapTo(targetPos); @@ -59,10 +62,11 @@ public class FallFromLadder } } } + [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.ClimbLadder))] class LadderPatch { - public static void Postfix(PlayerPhysics __instance, Ladder source/*, byte climbLadderSid*/) + public static void Postfix(PlayerPhysics __instance, Ladder source /*, byte climbLadderSid*/) { FallFromLadder.OnClimbLadder(__instance, source); } diff --git a/Patches/LobbyListPatch.cs b/Patches/LobbyListPatch.cs index 67d815b5f..8276720a0 100644 --- a/Patches/LobbyListPatch.cs +++ b/Patches/LobbyListPatch.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; -using HarmonyLib; +using HarmonyLib; using InnerNet; +using System; +using System.Collections.Generic; using UnityEngine; namespace TOHE; @@ -12,6 +12,7 @@ public static class FindAGameManagerUpdatePatch private static int buffer = 80; private static GameObject RefreshButton; private static GameObject InputDisplayGlyph; + public static void Postfix(FindAGameManager __instance) { if ((RefreshButton = GameObject.Find("RefreshButton")) != null) @@ -19,7 +20,9 @@ public static class FindAGameManagerUpdatePatch if ((InputDisplayGlyph = GameObject.Find("InputDisplayGlyph")) != null) InputDisplayGlyph.transform.localPosition = new Vector3(100f, 100f, 100f); - buffer--; if (buffer > 0) return; buffer = 80; + buffer--; + if (buffer > 0) return; + buffer = 80; __instance.RefreshList(); } } @@ -27,7 +30,7 @@ public static class FindAGameManagerUpdatePatch [HarmonyPatch(typeof(FindAGameManager), nameof(FindAGameManager.HandleList))] public static class FindAGameManagerHandleListPatch { - public static void Prefix(/*FindAGameManager __instance,*/ /*[HarmonyArgument(0)] InnerNetClient.TotalGameData totalGames,*/ [HarmonyArgument(1)] ref List games) + public static void Prefix( /*FindAGameManager __instance,*/ /*[HarmonyArgument(0)] InnerNetClient.TotalGameData totalGames,*/ [HarmonyArgument(1)] ref List games) { List newList = []; @@ -40,19 +43,19 @@ public static class FindAGameManagerHandleListPatch var color = game.Platform switch { Platforms.StandaloneItch or - Platforms.StandaloneWin10 or - Platforms.StandaloneEpicPC or - Platforms.StandaloneSteamPC => "#00a4ff", + Platforms.StandaloneWin10 or + Platforms.StandaloneEpicPC or + Platforms.StandaloneSteamPC => "#00a4ff", Platforms.Xbox or - Platforms.Switch or - Platforms.Playstation => "#dd001b", + Platforms.Switch or + Platforms.Playstation => "#dd001b", Platforms.IPhone or - Platforms.Android => "#68bc71", + Platforms.Android => "#68bc71", Platforms.Unknown or - _ => "#ffffff" + _ => "#ffffff" }; string str = Math.Abs(game.GameId).ToString(); @@ -63,6 +66,7 @@ public static class FindAGameManagerHandleListPatch newList.Add(game); } + games = newList; } -} +} \ No newline at end of file diff --git a/Patches/LogoAndStampPatch.cs b/Patches/LogoAndStampPatch.cs index 65a14e156..c0b3ca0c3 100644 --- a/Patches/LogoAndStampPatch.cs +++ b/Patches/LogoAndStampPatch.cs @@ -1,6 +1,6 @@ -using System.Collections; -using BepInEx.Unity.IL2CPP.Utils; +using BepInEx.Unity.IL2CPP.Utils; using HarmonyLib; +using System.Collections; using TMPro; using UnityEngine; using static TOHE.Translator; @@ -25,9 +25,11 @@ public static class CredentialsPatch { ViewBoosterPatch(__instance); } + break; } } + public static string BoosterData = string.Empty; public static string SponsersData = string.Empty; public static string DevsData = string.Empty; @@ -76,10 +78,10 @@ public static class CredentialsPatch SponsersData += "\n斯卡蒂Skadi"; SponsersData += "\nltemten"; SponsersData += $"\n\n({GetString("OnlyShowPart")})"; - } public static GameObject CreditsPopup; + static void ViewBoosterPatch(MainMenuManager __instance) { var template = __instance.transform.FindChild("StatsPopup"); @@ -144,7 +146,9 @@ public static class CredentialsPatch obj.transform.FindChild("Background").localScale = new Vector3(1.5f, 1f, 1f); obj.transform.FindChild("CloseButton").localPosition = new Vector3(-3.75f, 2.65f, 0); } + public static MainMenuManager instance; + public static void Postfix(MainMenuManager __instance) { InitCredentialsData(); diff --git a/Patches/MainMenuManagerPatch.cs b/Patches/MainMenuManagerPatch.cs index 078759363..c25725b5a 100644 --- a/Patches/MainMenuManagerPatch.cs +++ b/Patches/MainMenuManagerPatch.cs @@ -1,5 +1,5 @@ -using System; using HarmonyLib; +using System; using TMPro; using TOHE.Modules; using UnityEngine; @@ -13,6 +13,7 @@ namespace TOHE; public class MainMenuManagerPatch { public static GameObject template; + //public static GameObject qqButton; //public static GameObject discordButton; public static GameObject updateButton; @@ -28,7 +29,9 @@ public class MainMenuManagerPatch TitleLogoPatch.LoadingHint.SetActive(!Options.IsLoaded); TitleLogoPatch.LoadingHint.GetComponent().text = string.Format(GetString("LoadingWithPercentage"), Options.LoadingPercentage, Options.MainLoadingText, Options.RoleLoadingText); } - catch { } + catch + { + } } [HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start)), HarmonyPrefix] @@ -159,10 +162,7 @@ public class MainMenuManagerPatch spriteCreditsButton.sprite = Utils.LoadSprite("TOHE.Resources.Images.CreditsButton.png", 75f); passiveCreditsButton.OnClick = new ButtonClickedEvent(); - passiveCreditsButton.OnClick.AddListener((Action)(() => - { - CredentialsPatch.LogoPatch.CreditsPopup?.SetActive(true); - })); + passiveCreditsButton.OnClick.AddListener((Action)(() => { CredentialsPatch.LogoPatch.CreditsPopup?.SetActive(true); })); Application.targetFrameRate = Main.UnlockFPS.Value ? 165 : 60; } diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index 5800a0628..678714031 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -1,8 +1,8 @@ +using HarmonyLib; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using HarmonyLib; using TOHE.Roles.Crewmate; using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; diff --git a/Patches/OutroPatch.cs b/Patches/OutroPatch.cs index 297f9c33c..2bc9c331f 100644 --- a/Patches/OutroPatch.cs +++ b/Patches/OutroPatch.cs @@ -1,8 +1,8 @@ +using HarmonyLib; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using HarmonyLib; using TMPro; using TOHE.Modules; using TOHE.Roles.Impostor; diff --git a/Patches/PetActionsPatch.cs b/Patches/PetActionsPatch.cs index 69362f628..8e12e6369 100644 --- a/Patches/PetActionsPatch.cs +++ b/Patches/PetActionsPatch.cs @@ -1,17 +1,10 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using AmongUs.GameOptions; using HarmonyLib; -using TOHE.Modules; -using TOHE.Roles.Crewmate; using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; -using UnityEngine; -using static TOHE.Translator; -namespace TOHE; +namespace TOHE.Patches; /* * HUGE THANKS TO @@ -23,6 +16,7 @@ namespace TOHE; class LocalPetPatch { private static readonly Dictionary LastProcess = []; + public static bool Prefix(PlayerControl __instance) { if (!Options.UsePets.GetBool()) return true; @@ -53,6 +47,7 @@ class LocalPetPatch class ExternalRpcPetPatch { private static readonly Dictionary LastProcess = []; + public static void Prefix(PlayerPhysics __instance, [HarmonyArgument(0)] byte callID) { if (!Options.UsePets.GetBool() || !AmongUsClient.Instance.AmHost || (RpcCalls)callID != RpcCalls.Pet) return; @@ -82,6 +77,7 @@ class ExternalRpcPetPatch _ = new LateTask(() => { OnPetUse(pc); }, 0.2f, $"OnPetUse: {pc.GetNameWithRole().RemoveHtmlTags()}", false); } + public static void OnPetUse(PlayerControl pc) { if (pc == null || @@ -104,294 +100,27 @@ class ExternalRpcPetPatch if (pc.HasAbilityCD()) return; - PlayerControl[] AllAlivePlayers = Main.AllAlivePlayerControls; - bool hasKillTarget = false; PlayerControl target = SelectKillButtonTarget(pc); if (target != null) hasKillTarget = true; if (!pc.CanUseKillButton()) hasKillTarget = false; - switch (pc.GetCustomRole()) + if (pc.GetCustomRole().UsesPetInsteadOfKill() && hasKillTarget && pc.Data.RoleType != RoleTypes.Impostor) { - // Crewmates - - case CustomRoles.Doormaster: - Doormaster.OnEnterVent(pc); - break; - case CustomRoles.Sapper: - Sapper.OnShapeshift(pc); - break; - case CustomRoles.Tether: - Tether.OnEnterVent(pc, 0, true); - break; - case CustomRoles.CameraMan: - CameraMan.OnEnterVent(pc); - break; - case CustomRoles.Alchemist: - Alchemist.OnEnterVent(pc, 0, true); - break; - case CustomRoles.NiceHacker: - NiceHacker.OnEnterVent(pc); - break; - case CustomRoles.Druid: - Druid.OnEnterVent(pc, isPet: true); - break; - case CustomRoles.Tornado: - Tornado.SpawnTornado(pc); - break; - case CustomRoles.Sentinel: - Sentinel.StartPatrolling(pc); - break; - case CustomRoles.Convener: - Convener.UseAbility(pc, isPet: true); - break; - case CustomRoles.Perceiver: - Perceiver.UseAbility(pc); - break; - - case CustomRoles.Gaulois when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Gaulois.OnCheckMurder(pc, target); - break; - case CustomRoles.Aid when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Aid.OnCheckMurder(pc, target); - break; - case CustomRoles.Escort when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Escort.OnCheckMurder(pc, target); - break; - case CustomRoles.DonutDelivery when hasKillTarget: - pc.AddKCDAsAbilityCD(); - DonutDelivery.OnCheckMurder(pc, target); - break; - case CustomRoles.Analyzer when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Analyzer.OnCheckMurder(pc, target); - break; - case CustomRoles.Jailor when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Jailor.OnCheckMurder(pc, target); - break; - case CustomRoles.Sheriff when hasKillTarget: - pc.AddKCDAsAbilityCD(); - if (Sheriff.OnCheckMurder(pc, target)) pc.RpcCheckAndMurder(target); - break; - case CustomRoles.SwordsMan when hasKillTarget: - pc.AddKCDAsAbilityCD(); - if (SwordsMan.OnCheckMurder(pc)) pc.RpcCheckAndMurder(target); - break; - case CustomRoles.Witness when hasKillTarget: - pc.AddKCDAsAbilityCD(); - if (Witness.AllKillers.ContainsKey(target.PlayerId)) // Done with OnCheckMurder - pc.Notify(GetString("WitnessFoundKiller")); - else pc.Notify(GetString("WitnessFoundInnocent")); - break; - case CustomRoles.Medic when hasKillTarget: - Medic.OnCheckMurderFormedicaler(pc, target); // Done with OnCheckMurder - pc.AddKCDAsAbilityCD(); - break; - case CustomRoles.Monarch when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Monarch.OnCheckMurder(pc, target); - break; - case CustomRoles.CopyCat when hasKillTarget: - pc.AddKCDAsAbilityCD(); - if (CopyCat.OnCheckMurder(pc, target)) pc.RpcCheckAndMurder(target); - break; - case CustomRoles.Farseer when hasKillTarget: // Done with OnCheckMurder - pc.AddAbilityCD(Farseer.FarseerRevealTime.GetInt()); - if (!Main.isRevealed[(pc.PlayerId, target.PlayerId)] && !Farseer.FarseerTimer.ContainsKey(pc.PlayerId)) - { - Farseer.FarseerTimer.TryAdd(pc.PlayerId, (target, 0f)); - Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: target, ForceLoop: true); - RPC.SetCurrentRevealTarget(pc.PlayerId, target.PlayerId); - } - - break; - case CustomRoles.Deputy when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Deputy.OnCheckMurder(pc, target); - break; - case CustomRoles.Crusader when hasKillTarget: - pc.AddKCDAsAbilityCD(); - Crusader.OnCheckMurder(pc, target); - break; - - // Impostors - - case CustomRoles.Sniper: - Sniper.OnShapeshift(pc, !Sniper.IsAim[pc.PlayerId]); - break; - case CustomRoles.FireWorks: - FireWorks.ShapeShiftState(pc, true); - break; - case CustomRoles.Assassin: - Assassin.OnShapeshift(pc, true); - break; - case CustomRoles.Undertaker: - Undertaker.OnShapeshift(pc, true); - break; - case CustomRoles.RiftMaker: - RiftMaker.OnShapeshift(pc, true); - break; - case CustomRoles.Nuker: - Logger.Info("Nuker explosion", "Boom"); - CustomSoundsManager.RPCPlayCustomSoundAll("Boom"); - foreach (PlayerControl tg in Main.AllPlayerControls) - { - if (!tg.IsModClient()) tg.KillFlash(); - var pos = pc.Pos(); - var dis = Vector2.Distance(pos, tg.Pos()); - - if (!tg.IsAlive() || Pelican.IsEaten(tg.PlayerId) || Medic.ProtectList.Contains(tg.PlayerId) || tg.inVent || tg.Is(CustomRoles.Pestilence)) continue; - if (dis > Options.NukeRadius.GetFloat()) continue; - if (tg.PlayerId == pc.PlayerId) continue; - - tg.Suicide(PlayerState.DeathReason.Bombed, pc); - } - - _ = new LateTask(() => - { - var totalAlive = AllAlivePlayers.Length; - if (totalAlive > 1 && !GameStates.IsEnded) - { - pc.Suicide(PlayerState.DeathReason.Bombed); - } - - Utils.NotifyRoles(ForceLoop: true); - }, 1.5f, "Nuke"); - break; - case CustomRoles.QuickShooter: - QuickShooter.OnShapeshift(pc, true); - break; - case CustomRoles.Disperser: - Disperser.DispersePlayers(pc); - break; - case CustomRoles.Twister: - Twister.TwistPlayers(pc, true); - break; - case CustomRoles.Swiftclaw: - Swiftclaw.OnPet(pc); - break; - - case CustomRoles.Refugee when hasKillTarget: - pc.AddKCDAsAbilityCD(); + pc.AddKCDAsAbilityCD(); + if (Main.PlayerStates[pc.PlayerId].Role.OnCheckMurder(pc, target)) + { pc.RpcCheckAndMurder(target); - pc.SetKillCooldown(); - break; + } - // Neutrals - - case CustomRoles.Glitch: - Glitch.Mimic(pc); - break; - case CustomRoles.Magician: - Magician.UseCard(pc); - break; - case CustomRoles.WeaponMaster: - WeaponMaster.SwitchMode(); - break; - case CustomRoles.Enderman: - Enderman.MarkPosition(); - break; - case CustomRoles.Hookshot: - Hookshot.ExecuteAction(); - break; - case CustomRoles.Sprayer: - Sprayer.PlaceTrap(); - break; - case CustomRoles.Arsonist when pc.CanUseImpostorVentButton(): - if (pc.IsDouseDone()) - { - CustomSoundsManager.RPCPlayCustomSoundAll("Boom"); - foreach (PlayerControl player in Main.AllAlivePlayerControls) - { - if (player != pc) - { - player.Suicide(PlayerState.DeathReason.Torched, pc); - } - } - - foreach (PlayerControl player in Main.AllPlayerControls) - { - player.KillFlash(); - } - - CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); - CustomWinnerHolder.WinnerIds.Add(pc.PlayerId); - break; - } - - if (Options.ArsonistCanIgniteAnytime.GetBool()) - { - var douseCount = Utils.GetDousedPlayerCount(pc.PlayerId).Item1; - if (douseCount >= Options.ArsonistMinPlayersToIgnite.GetInt()) // Don't check for max, since the player would not be able to ignite at all if they somehow get more players doused than the max - { - if (douseCount > Options.ArsonistMaxPlayersToIgnite.GetInt()) Logger.Warn("Arsonist Ignited with more players doused than the maximum amount in the settings", "Arsonist Ignite"); - foreach (PlayerControl player in Main.AllAlivePlayerControls) - { - if (!pc.IsDousedPlayer(player)) - continue; - player.KillFlash(); - player.Suicide(PlayerState.DeathReason.Torched, pc); - } - - var apc = Main.AllAlivePlayerControls.Length; - if (apc == 1) - { - CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); - CustomWinnerHolder.WinnerIds.Add(pc.PlayerId); - } - - if (apc == 2) - { - foreach (var player in Main.AllAlivePlayerControls.Where(p => p.PlayerId != pc.PlayerId).ToArray()) - { - if (!player.GetCustomRole().IsImpostor() && !player.GetCustomRole().IsNeutralKilling()) - { - CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); - CustomWinnerHolder.WinnerIds.Add(pc.PlayerId); - } - } - } - } - } - - break; - - case CustomRoles.Necromancer when hasKillTarget && Main.KillTimers[pc.PlayerId] <= 0: - if (pc.Data.RoleType != RoleTypes.Impostor) pc.AddKCDAsAbilityCD(); - Necromancer.OnCheckMurder(pc, target); - break; - case CustomRoles.Deathknight when hasKillTarget: - if (pc.Data.RoleType != RoleTypes.Impostor) pc.AddKCDAsAbilityCD(); - Deathknight.OnCheckMurder(pc, target); - break; - - // Message when no ability is triggered - - default: - int x = IRandom.Instance.Next(1, 16); - string suffix; - if (x >= 14) - { - x -= 13; - suffix = pc.GetCustomRole().GetCustomRoleTypes() switch - { - CustomRoleTypes.Impostor => $"Imp{x}", - CustomRoleTypes.Neutral => $"Neutral{x}", - CustomRoleTypes.Crewmate => x == 1 ? "Crew" : pc.GetTaskState().hasTasks && pc.GetTaskState().IsTaskFinished ? "CrewTaskDone" : "CrewWithTasksLeft", - _ => x.ToString(), - }; - } - else suffix = x.ToString(); - - pc.Notify(GetString($"NoPetActionMsg{suffix}")); - break; + if (pc.Is(CustomRoles.Refugee)) pc.SetKillCooldown(); + } + else + { + Main.PlayerStates[pc.PlayerId].Role.OnPet(pc); } - if (pc.HasAbilityCD() || (pc.Is(CustomRoles.Sniper) && Sniper.IsAim[pc.PlayerId])) return; + if (pc.HasAbilityCD() || (pc.Is(CustomRoles.Sniper) && Main.PlayerStates[pc.PlayerId].Role is Sniper { IsAim: true })) return; pc.AddAbilityCD(); } diff --git a/Patches/PlayerContorolPatch.cs b/Patches/PlayerContorolPatch.cs index b68209fe6..1648587d0 100644 --- a/Patches/PlayerContorolPatch.cs +++ b/Patches/PlayerContorolPatch.cs @@ -1,12 +1,11 @@ +using AmongUs.GameOptions; +using HarmonyLib; +using Hazel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using AmongUs.GameOptions; -using HarmonyLib; -using Hazel; -using InnerNet; using TMPro; using TOHE.Modules; using TOHE.Roles.AddOns.Common; @@ -111,8 +110,7 @@ class CheckMurderPatch || target.inMovingPlat || target.MyPhysics.Animations.IsPlayingEnterVentAnimation() || target.MyPhysics.Animations.IsPlayingAnyLadderAnimation() - || target.onLadder - ) + || target.onLadder) { Logger.Info("The target is in a state where they cannot be killed, kill canceled.", "CheckMurder"); return false; @@ -164,7 +162,6 @@ class CheckMurderPatch killer.ResetKillCooldown(); - //キル可能判定 if (killer.PlayerId != target.PlayerId && !killer.CanUseKillButton()) { Logger.Info(killer.GetNameWithRole().RemoveHtmlTags() + " cannot use their kill button, the kill was blocked", "CheckMurder"); @@ -189,335 +186,29 @@ class CheckMurderPatch return Mastermind.ForceKillForManipulatedPlayer(killer, target); } - if (target.Is(CustomRoles.Spy)) Spy.OnKillAttempt(killer, target); + if (target.Is(CustomRoles.Spy) && !Spy.OnKillAttempt(killer, target)) return false; if (Penguin.IsVictim(target)) return false; - //実際のキラーとkillerが違う場合の入れ替え処理 - if (Sniper.IsEnable) Sniper.TryGetSniper(target.PlayerId, ref killer); + Sniper.TryGetSniper(target.PlayerId, ref killer); if (killer != __instance) Logger.Info($"Real Killer: {killer.GetNameWithRole().RemoveHtmlTags()}", "CheckMurder"); - //鹈鹕肚子里的人无法击杀 if (Pelican.IsEaten(target.PlayerId)) return false; - //阻止对活死人的操作 - - // 赝品检查 - //if (Counterfeiter.OnClientMurder(killer)) return false; if (Glitch.hackedIdList.ContainsKey(killer.PlayerId)) { killer.Notify(string.Format(GetString("HackedByGlitch"), "Kill")); return false; } - if (Pursuer.IsEnable && Pursuer.OnClientMurder(killer)) return false; + if (Pursuer.OnClientMurder(killer)) return false; - if (killer.PlayerId != target.PlayerId) - { - switch (killer.GetCustomRole()) - { - case CustomRoles.BountyHunter: - BountyHunter.OnCheckMurder(killer, target); - break; - case CustomRoles.Kamikaze: - if (!Kamikaze.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Reckless: - Reckless.OnCheckMurder(killer); - break; - case CustomRoles.YinYanger: - if (!YinYanger.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Magician: - Magician.OnCheckMurder(killer); - break; - case CustomRoles.Analyzer: - Analyzer.OnCheckMurder(killer, target); - return false; - case CustomRoles.DonutDelivery: - DonutDelivery.OnCheckMurder(killer, target); - return false; - case CustomRoles.Mycologist: - if (!Mycologist.OnCheckMurder(target)) return false; - break; - case CustomRoles.Bubble: - Bubble.OnCheckMurder(target); - return false; - case CustomRoles.Hookshot: - if (!Hookshot.OnCheckMurder(target)) return false; - break; - case CustomRoles.Gaulois: - Gaulois.OnCheckMurder(killer, target); - return false; - case CustomRoles.Escort: - Escort.OnCheckMurder(killer, target); - return false; - case CustomRoles.WeaponMaster: - if (!WeaponMaster.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Cantankerous: - if (!Cantankerous.OnCheckMurder(killer)) return false; - break; - case CustomRoles.Postman: - Postman.OnCheckMurder(killer, target); - return false; - case CustomRoles.SoulHunter: - if (!SoulHunter.OnCheckMurder(target)) return false; - break; - case CustomRoles.Vengeance: - if (!Vengeance.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Stealth: - Stealth.OnCheckMurder(killer, target); - break; - case CustomRoles.Consort: - if (!Consort.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Mafioso: - if (!Mafioso.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Nullifier: - if (Nullifier.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Chronomancer: - Chronomancer.OnCheckMurder(killer, target); - break; - case CustomRoles.Penguin: - if (!Penguin.OnCheckMurderAsKiller(target)) return false; - break; - case CustomRoles.Sapper: - return false; - case CustomRoles.Saboteur: - if (Math.Abs(Main.AllPlayerKillCooldown[killer.PlayerId] - Options.SaboteurCD.GetFloat()) > 0.5f) - { - Main.AllPlayerKillCooldown[killer.PlayerId] = Options.SaboteurCD.GetFloat(); - killer.SyncSettings(); - } - - break; - case CustomRoles.Gambler: - if (!Gambler.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Mastermind: - if (!Mastermind.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Hitman: - if (!Hitman.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Aid: - if (!Aid.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.HeadHunter: - HeadHunter.OnCheckMurder(killer, target); - break; - case CustomRoles.SerialKiller: - SerialKiller.OnCheckMurder(killer); - break; - case CustomRoles.Glitch: - if (!Glitch.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Eraser: - if (!Eraser.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Bandit: - if (!Bandit.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Vampire: - if (!Vampire.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Pyromaniac: - if (!Pyromaniac.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Agitater: - if (!Agitater.OnCheckMurder(killer, target)) - return false; - break; - case CustomRoles.Eclipse: - Eclipse.OnCheckMurder(killer); - break; - case CustomRoles.Jailor: - if (!Jailor.OnCheckMurder(killer, target)) - return false; - break; - case CustomRoles.Poisoner: - if (!Poisoner.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Assassin: - if (!Assassin.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Undertaker: - if (!Undertaker.OnCheckMurder(killer, target)) return false; - break; - //case CustomRoles.Famine: - // Baker.FamineKilledTasks(target.PlayerId); - // break; - - case CustomRoles.Witch: - if (!Witch.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.HexMaster: - if (!HexMaster.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.PlagueDoctor: - if (!PlagueDoctor.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Gangster: - if (Gangster.OnCheckMurder(killer, target)) - return false; - break; - case CustomRoles.BallLightning: - if (BallLightning.CheckBallLightningMurder(killer, target)) - return false; - break; - case CustomRoles.Greedier: - Greedier.OnCheckMurder(killer); - break; - case CustomRoles.Imitator: - Imitator.OnCheckMurder(killer); - break; - case CustomRoles.QuickShooter: - QuickShooter.QuickShooterKill(killer); - break; - case CustomRoles.Sans: - Sans.OnCheckMurder(killer); - break; - case CustomRoles.Juggernaut: - Juggernaut.OnCheckMurder(killer); - break; - //case CustomRoles.Reverie: - // Reverie.OnCheckMurder(killer); - // break; - case CustomRoles.Hangman: - if (!Hangman.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Swooper: - if (!Swooper.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Wraith: - if (!Wraith.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Werewolf: - Werewolf.OnCheckMurder(killer, target); - break; - case CustomRoles.Lurker: - Lurker.OnCheckMurder(killer); - break; - case CustomRoles.Crusader: - Crusader.OnCheckMurder(killer, target); - return false; - - //==========中立阵营==========// - case CustomRoles.PlagueBearer: - if (!PlagueBearer.OnCheckMurder(killer, target)) - return false; - break; - //case CustomRoles.Pirate: - // if (!Pirate.OnCheckMurder(killer, target)) - // return false; - // break; - - case CustomRoles.Arsonist: - killer.SetKillCooldown(Options.ArsonistDouseTime.GetFloat()); - if (!Main.isDoused[(killer.PlayerId, target.PlayerId)] && !Main.ArsonistTimer.ContainsKey(killer.PlayerId)) - { - Main.ArsonistTimer.Add(killer.PlayerId, (target, 0f)); - NotifyRoles(SpecifySeer: __instance, SpecifyTarget: target, ForceLoop: true); - RPC.SetCurrentDousingTarget(killer.PlayerId, target.PlayerId); - } - - return false; - case CustomRoles.Pelican: - if (Pelican.CanEat(killer, target.PlayerId)) - { - Pelican.EatPlayer(killer, target); - //killer.RpcGuardAndKill(killer); - killer.SetKillCooldown(); - killer.RPCPlayCustomSound("Eat"); - target.RPCPlayCustomSound("Eat"); - } - - return false; - case CustomRoles.FFF: - if (!FFF.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Gamer: - Gamer.CheckGamerMurder(killer, target); - return false; - case CustomRoles.DarkHide: - DarkHide.OnCheckMurder(killer, target); - break; - case CustomRoles.Totocalcio: - Totocalcio.OnCheckMurder(killer, target); - return false; - case CustomRoles.Romantic: - if (!Romantic.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.VengefulRomantic: - if (!VengefulRomantic.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Succubus: - Succubus.OnCheckMurder(killer, target); - return false; - case CustomRoles.Necromancer: - Necromancer.OnCheckMurder(killer, target); - return false; - case CustomRoles.Deathknight: - Deathknight.OnCheckMurder(killer, target); - return false; - //case CustomRoles.CursedSoul: - // CursedSoul.OnCheckMurder(killer, target); - // return false; - case CustomRoles.Amnesiac: - Amnesiac.OnCheckMurder(killer, target); - return false; - case CustomRoles.Monarch: - Monarch.OnCheckMurder(killer, target); - return false; - case CustomRoles.Deputy: - Deputy.OnCheckMurder(killer, target); - return false; - case CustomRoles.Jackal: - if (Jackal.OnCheckMurder(killer, target)) - return false; - break; - - //==========船员职业==========// - case CustomRoles.Sheriff: - if (!Sheriff.OnCheckMurder(killer, target)) - return false; - break; - case CustomRoles.CopyCat: - if (!CopyCat.OnCheckMurder(killer, target)) - return false; - break; - - case CustomRoles.SwordsMan: - if (!SwordsMan.OnCheckMurder(killer)) - return false; - break; - case CustomRoles.Medic: - Medic.OnCheckMurderFormedicaler(killer, target); - return false; - //case CustomRoles.Counterfeiter: - // if (Counterfeiter.CanBeClient(target) && Counterfeiter.CanSeel(killer.PlayerId)) - // Counterfeiter.SeelToClient(killer, target); - // return false; - case CustomRoles.EvilDiviner: - if (!EvilDiviner.OnCheckMurder(killer, target)) return false; - break; - case CustomRoles.Ritualist: - if (!Ritualist.OnCheckMurder(killer, target)) return false; - break; - } - } + if (killer.PlayerId != target.PlayerId && !Main.PlayerStates[killer.PlayerId].Role.OnCheckMurder(killer, target)) return false; if (!killer.RpcCheckAndMurder(target, true)) return false; - if (killer.Is(CustomRoles.Virus)) Virus.OnCheckMurder( /*killer,*/ target); - else if (killer.Is(CustomRoles.Spiritcaller)) Spiritcaller.OnCheckMurder(target); - if (killer.Is(CustomRoles.Unlucky)) { var Ue = IRandom.Instance; @@ -585,9 +276,6 @@ class CheckMurderPatch // Romantic partner is protected if (Romantic.PartnerId == target.PlayerId && Romantic.IsPartnerProtected) return false; - - if (Merchant.OnClientMurder(killer, target)) return false; - if (Medic.OnAnyoneCheckMurder(killer, target)) return false; @@ -599,12 +287,12 @@ class CheckMurderPatch if (killer.Is(CustomRoles.Refugee) && target.Is(CustomRoleTypes.Impostor)) return false; - if (SoulHunter.IsTargetBlocked && SoulHunter.CurrentTarget.ID == killer.PlayerId && target.Is(CustomRoles.SoulHunter)) + if (SoulHunter.IsSoulHunterTarget(killer.PlayerId) && target.Is(CustomRoles.SoulHunter)) { killer.Notify(GetString("SoulHunterTargetNotifyNoKill")); _ = new LateTask(() => { - if (SoulHunter.CurrentTarget.ID == killer.PlayerId) killer.Notify(string.Format(GetString("SoulHunterTargetNotify"), SoulHunter.SoulHunter_.GetRealName()), 300f); + if (SoulHunter.IsSoulHunterTarget(killer.PlayerId)) killer.Notify(string.Format(GetString("SoulHunterTargetNotify"), SoulHunter.GetSoulHunter(killer.PlayerId).SoulHunter_.GetRealName()), 300f); }, 4f, log: false); return false; } @@ -629,9 +317,6 @@ class CheckMurderPatch if (killer.Is(CustomRoles.Sidekick) && target.Is(CustomRoles.Recruit) && !Options.SidekickCanKillSidekick.GetBool()) return false; - if (Pestilence.OnCheckMurderPestilence(killer, target)) - return false; - if (Jackal.ResetKillCooldownWhenSbGetKilled.GetBool() && !killer.Is(CustomRoles.Sidekick) && !target.Is(CustomRoles.Sidekick) && !killer.Is(CustomRoles.Jackal) && !target.Is(CustomRoles.Jackal) && !GameStates.IsMeeting) Jackal.AfterPlayerDiedTask(killer); @@ -677,47 +362,9 @@ class CheckMurderPatch break; case CustomRoles.Monarch when killer.Is(CustomRoles.Knighted): return false; - case CustomRoles.WeaponMaster when WeaponMaster.OnAttack(): case CustomRoles.Gambler when Gambler.isShielded.ContainsKey(target.PlayerId): - case CustomRoles.Alchemist when Alchemist.IsProtected: - case CustomRoles.Nightmare when !Nightmare.CanBeKilled: killer.SetKillCooldown(time: 5f); return false; - case CustomRoles.Vengeance when !Vengeance.OnKillAttempt(killer, target): - return false; - case CustomRoles.Ricochet when !Ricochet.OnKillAttempt(killer, target): - return false; - case CustomRoles.Jinx: - if (Main.JinxSpellCount[target.PlayerId] <= 0) break; - if (killer.Is(CustomRoles.Pestilence)) break; - if (killer == target) break; - var kcd2 = Main.KillTimers[target.PlayerId] + Main.AllPlayerKillCooldown[target.PlayerId]; - killer.RpcGuardAndKill(target); - Main.JinxSpellCount[target.PlayerId] -= 1; - RPC.SendRPCJinxSpellCount(target.PlayerId); - if (Jinx.killAttacker.GetBool()) - { - Logger.Info($"{target.GetNameWithRole().RemoveHtmlTags()} : {Main.JinxSpellCount[target.PlayerId]} jixes remain", "Jinx"); - Main.PlayerStates[killer.PlayerId].deathReason = PlayerState.DeathReason.Jinx; - killer.SetRealKiller(target); - target.Kill(killer); - } - - target.SetKillCooldown(time: kcd2); - return false; - case CustomRoles.Gamer: - if (!Gamer.CheckMurder(killer, target)) - return false; - break; - case CustomRoles.BloodKnight: - if (BloodKnight.InProtect(target.PlayerId)) - { - killer.RpcGuardAndKill(target); - target.Notify(GetString("BKOffsetKill")); - return false; - } - - break; case CustomRoles.Spiritcaller: if (Spiritcaller.InProtect(target)) { @@ -729,7 +376,7 @@ class CheckMurderPatch } // Bodyguard - if (killer.PlayerId != target.PlayerId && (from pc1 in Main.AllAlivePlayerControls.Where(x => x.PlayerId != target.PlayerId) let pos1 = target.Pos() let dis = Vector2.Distance(pos, pc.Pos()) where !(dis > Options.BodyguardProtectRadius.GetFloat()) select pc).Any(pc => pc.Is(CustomRoles.Bodyguard) && !Bodyguard.OnCheckMurderAsTarget(pc, killer))) + if (killer.PlayerId != target.PlayerId && (from pc in Main.AllAlivePlayerControls.Where(x => x.PlayerId != target.PlayerId) let pos = target.Pos() let dis = Vector2.Distance(pos, pc.Pos()) where !(dis > Options.BodyguardProtectRadius.GetFloat()) select pc).Any(pc => pc.Is(CustomRoles.Bodyguard) && !Bodyguard.OnCheckMurderAsTarget(pc, killer))) { return false; } @@ -756,14 +403,13 @@ class CheckMurderPatch return false; } - if (Sentinel.IsEnable) - { - if (!Sentinel.OnAnyoneCheckMurder(killer)) - return false; - } + if (!Sentinel.OnAnyoneCheckMurder(killer)) + return false; + + if (!Main.PlayerStates[target.PlayerId].Role.OnCheckMurderAsTarget(killer, target)) return false; if (!check) killer.Kill(target); - if (killer.Is(CustomRoles.Doppelganger)) Doppelganger.OnCheckMurder(killer, target); + if (killer.Is(CustomRoles.Doppelganger)) (Main.PlayerStates[killer.PlayerId].Role as Doppelganger)?.OnCheckMurder(killer, target); return true; } } @@ -797,12 +443,9 @@ class MurderPlayerPatch PlagueDoctor.OnAnyMurder(); // Replacement process when the actual killer and killer are different - if (Sniper.IsEnable) + if (Sniper.TryGetSniper(target.PlayerId, ref killer)) { - if (Sniper.TryGetSniper(target.PlayerId, ref killer)) - { - Main.PlayerStates[target.PlayerId].deathReason = PlayerState.DeathReason.Sniped; - } + Main.PlayerStates[target.PlayerId].deathReason = PlayerState.DeathReason.Sniped; } if (killer.Is(CustomRoles.Sniper)) @@ -855,22 +498,7 @@ class MurderPlayerPatch break; } - switch (killer.GetCustomRole()) - { - case CustomRoles.SwordsMan: - if (killer != target) - SwordsMan.OnMurder(killer); - break; - case CustomRoles.BloodKnight: - BloodKnight.OnMurderPlayer(killer, target); - break; - case CustomRoles.Maverick: - Maverick.NumOfKills++; - break; - case CustomRoles.Wildling: - Wildling.OnMurderPlayer(killer, target); - break; - } + Main.PlayerStates[killer.PlayerId].Role.OnMurder(killer, target); if (killer.Is(CustomRoles.TicketsStealer) && killer.PlayerId != target.PlayerId) killer.Notify(string.Format(GetString("TicketsStealerGetTicket"), ((Main.AllPlayerControls.Count(x => x.GetRealKiller()?.PlayerId == killer.PlayerId) + 1) * Options.TicketsPerKill.GetFloat()).ToString("0.0#####"))); @@ -907,9 +535,10 @@ class MurderPlayerPatch } } - if (Mediumshiper.IsEnable) - foreach (var pc in Main.AllAlivePlayerControls.Where(x => x.Is(CustomRoles.Mediumshiper)).ToArray()) - pc.Notify(ColorString(GetRoleColor(CustomRoles.Mediumshiper), GetString("MediumshiperKnowPlayerDead"))); + foreach (var pc in Main.AllAlivePlayerControls.Where(x => x.Is(CustomRoles.Mediumshiper))) + { + pc.Notify(ColorString(GetRoleColor(CustomRoles.Mediumshiper), GetString("MediumshiperKnowPlayerDead"))); + } AfterPlayerDeathTasks(target); @@ -964,6 +593,8 @@ class ShapeshiftPatch Logger.Info($"{shapeshifter?.GetNameWithRole()} => {target?.GetNameWithRole()}", "Shapeshift"); + if (shapeshifter == null || target == null) return true; + var shapeshifting = shapeshifter.PlayerId != target.PlayerId; if (Main.CheckShapeshift.TryGetValue(shapeshifter.PlayerId, out var last) && last == shapeshifting) @@ -975,8 +606,6 @@ class ShapeshiftPatch Main.CheckShapeshift[shapeshifter.PlayerId] = shapeshifting; Main.ShapeshiftTarget[shapeshifter.PlayerId] = target.PlayerId; - if (Sniper.IsEnable) Sniper.OnShapeshift(shapeshifter, shapeshifting); - if (!AmongUsClient.Instance.AmHost) return true; if (!shapeshifting) Camouflage.RpcSetSkin(shapeshifter); @@ -984,176 +613,14 @@ class ShapeshiftPatch if (!Pelican.IsEaten(shapeshifter.PlayerId) && !GameStates.IsVoting) { - switch (shapeshifter.GetCustomRole()) - { - case CustomRoles.EvilTracker: - EvilTracker.OnShapeshift(shapeshifter, target, shapeshifting); - isSSneeded = false; - break; - case CustomRoles.Kidnapper: - Kidnapper.OnShapeshift(shapeshifter, target); - isSSneeded = false; - break; - case CustomRoles.Swapster: - Swapster.OnShapeshift(shapeshifter, target); - isSSneeded = false; - break; - case CustomRoles.RiftMaker: - RiftMaker.OnShapeshift(shapeshifter, shapeshifting); - isSSneeded = false; - break; - case CustomRoles.Hitman: - Hitman.OnShapeshift(shapeshifter, target, shapeshifting); - isSSneeded = false; - break; - case CustomRoles.Duellist: - Duellist.OnShapeshift(shapeshifter, target); - isSSneeded = false; - break; - case CustomRoles.FireWorks: - FireWorks.ShapeShiftState(shapeshifter, shapeshifting); - isSSneeded = false; - break; - case CustomRoles.Penguin: - return false; - case CustomRoles.Sapper: - Sapper.OnShapeshift(shapeshifter); - isSSneeded = false; - break; - case CustomRoles.Blackmailer: - Blackmailer.ForBlackmailer.Add(target.PlayerId); - isSSneeded = false; - break; - case CustomRoles.Librarian: - isSSneeded = Librarian.OnShapeshift(shapeshifter, shapeshifting); - break; - case CustomRoles.Bomber: - if (shapeshifting) - { - Logger.Info("Bomber explosion", "Boom"); - CustomSoundsManager.RPCPlayCustomSoundAll("Boom"); - foreach (PlayerControl tg in Main.AllPlayerControls) - { - if (!tg.IsModClient()) - tg.KillFlash(); - var pos = shapeshifter.transform.position; - var dis = Vector2.Distance(pos, tg.Pos()); - if (!tg.IsAlive() || Pelican.IsEaten(tg.PlayerId) || Medic.ProtectList.Contains(tg.PlayerId) || (tg.Is(CustomRoleTypes.Impostor) && Options.ImpostorsSurviveBombs.GetBool()) || tg.inVent || tg.Is(CustomRoles.Pestilence)) continue; - if (dis > Options.BomberRadius.GetFloat()) continue; - if (tg.PlayerId == shapeshifter.PlayerId) continue; - tg.Suicide(PlayerState.DeathReason.Bombed, shapeshifter); - } - - _ = new LateTask(() => - { - var totalAlive = Main.AllAlivePlayerControls.Length; - if (Options.BomberDiesInExplosion.GetBool() && totalAlive > 1 && !GameStates.IsEnded) - { - shapeshifter.Suicide(PlayerState.DeathReason.Bombed); - } - - //else - //{ - // shapeshifter.CmdCheckRevertShapeshift(false); - //} - NotifyRoles(ForceLoop: true); - }, 1.5f, "Bomber Suiscide"); - } - - isSSneeded = false; - //if (Options.BomberDiesInExplosion.GetBool()) isSSneeded = false; - break; - case CustomRoles.Nuker: - if (shapeshifting) - { - Logger.Info("Nuker explosion", "Boom"); - CustomSoundsManager.RPCPlayCustomSoundAll("Boom"); - foreach (PlayerControl tg in Main.AllPlayerControls) - { - if (!tg.IsModClient()) - tg.KillFlash(); - var pos = shapeshifter.transform.position; - var dis = Vector2.Distance(pos, tg.Pos()); - if (!tg.IsAlive() || Pelican.IsEaten(tg.PlayerId) || Medic.ProtectList.Contains(tg.PlayerId) || tg.inVent || tg.Is(CustomRoles.Pestilence)) continue; - if (dis > Options.NukeRadius.GetFloat()) continue; - if (tg.PlayerId == shapeshifter.PlayerId) continue; - tg.Suicide(PlayerState.DeathReason.Bombed, shapeshifter); - } - - _ = new LateTask(() => - { - var totalAlive = Main.AllAlivePlayerControls.Length; - if (totalAlive > 1 && !GameStates.IsEnded) - { - shapeshifter.Suicide(PlayerState.DeathReason.Bombed); - } - - //else if (!shapeshifter.IsModClient()) - //{ - // shapeshifter.CmdCheckRevertShapeshift(false); - //} - NotifyRoles(ForceLoop: true); - }, 1.5f, "Nuke"); - } - - isSSneeded = false; - break; - case CustomRoles.Assassin: - Assassin.OnShapeshift(shapeshifter, shapeshifting); - isSSneeded = false; - break; - case CustomRoles.Undertaker: - Undertaker.OnShapeshift(shapeshifter, shapeshifting); - isSSneeded = false; - break; - case CustomRoles.QuickShooter: - QuickShooter.OnShapeshift(shapeshifter, shapeshifting); - isSSneeded = false; - break; - case CustomRoles.Camouflager: - if (shapeshifting) - Camouflager.OnShapeshift(shapeshifter, shapeshifting); - if (!shapeshifting) - Camouflager.OnReportDeadBody(); - break; - case CustomRoles.Hangman: - if (shapeshifter.GetAbilityUseLimit() < 1 && shapeshifting) shapeshifter.SetKillCooldown(Hangman.ShapeshiftDuration.GetFloat() + 1f); - break; - case CustomRoles.Hacker: - Hacker.OnShapeshift(shapeshifter, shapeshifting, target); - isSSneeded = false; - break; - case CustomRoles.Disperser: - if (shapeshifting) - Disperser.DispersePlayers(shapeshifter); - isSSneeded = false; - break; - case CustomRoles.Dazzler: - if (shapeshifting) - Dazzler.OnShapeshift(shapeshifter, target); - isSSneeded = false; - break; - case CustomRoles.Deathpact: - if (shapeshifting) - Deathpact.OnShapeshift(shapeshifter, target); - isSSneeded = false; - break; - case CustomRoles.Devourer: - if (shapeshifting) - Devourer.OnShapeshift(shapeshifter, target); - isSSneeded = false; - break; - case CustomRoles.Twister: - Twister.TwistPlayers(shapeshifter, shapeshifting); - isSSneeded = false; - break; - } + isSSneeded = Main.PlayerStates[shapeshifter.PlayerId].Role.OnShapeshift(shapeshifter, target, shapeshifting); } + if (shapeshifter.Is(CustomRoles.Hangman) && shapeshifter.GetAbilityUseLimit() < 1 && shapeshifting) shapeshifter.SetKillCooldown(Hangman.ShapeshiftDuration.GetFloat() + 1f); if (shapeshifter.Is(CustomRoles.Camouflager) && !shapeshifting) Camouflager.Reset(); // Forced rewriting in case the name cannot be corrected due to the timing of canceling the transformation being off. - if (!shapeshifting && !shapeshifter.Is(CustomRoles.Glitch)) + if (!shapeshifting && !shapeshifter.Is(CustomRoles.Glitch) && isSSneeded) { _ = new LateTask(() => { NotifyRoles(NoCache: true); }, 1.2f, "ShapeShiftNotify"); @@ -1236,12 +703,12 @@ class ReportDeadBodyPatch { if (__instance.Is(CustomRoles.Jester) && !Options.JesterCanUseButton.GetBool()) return false; if (__instance.Is(CustomRoles.NiceSwapper) && !NiceSwapper.CanStartMeeting.GetBool()) return false; - if (SoulHunter.IsTargetBlocked && __instance.PlayerId == SoulHunter.CurrentTarget.ID) + if (SoulHunter.IsSoulHunterTarget(__instance.PlayerId)) { __instance.Notify(GetString("SoulHunterTargetNotifyNoMeeting")); _ = new LateTask(() => { - if (SoulHunter.CurrentTarget.ID == __instance.PlayerId) __instance.Notify(string.Format(GetString("SoulHunterTargetNotify"), SoulHunter.SoulHunter_.GetRealName()), 300f); + if (SoulHunter.IsSoulHunterTarget(__instance.PlayerId)) __instance.Notify(string.Format(GetString("SoulHunterTargetNotify"), SoulHunter.GetSoulHunter(__instance.PlayerId).SoulHunter_.GetRealName()), 300f); }, 4f, log: false); return false; } @@ -1256,40 +723,6 @@ class ReportDeadBodyPatch if (!Main.PlayerStates[__instance.PlayerId].Role.CheckReportDeadBody(__instance, target, killer)) return false; - switch (__instance.GetCustomRole()) - { - case CustomRoles.Vulture: - long now = TimeStamp; - if ((Vulture.AbilityLeftInRound[__instance.PlayerId] > 0) && (now - Vulture.LastReport[__instance.PlayerId] > (long)Vulture.VultureReportCD.GetFloat())) - { - Vulture.LastReport[__instance.PlayerId] = now; - Vulture.OnReportDeadBody(__instance, target); - __instance.Notify(GetString("VultureReportBody")); - if (Vulture.AbilityLeftInRound[__instance.PlayerId] > 0) - { - _ = new LateTask(() => - { - if (GameStates.IsInTask) - { - __instance.Notify(GetString("VultureCooldownUp")); - } - }, Vulture.VultureReportCD.GetFloat(), "Vulture CD"); - } - - Logger.Info($"{__instance.GetRealName()} ate {target.PlayerName} corpse", "Vulture"); - return false; - } - - break; - case CustomRoles.Medusa when Main.KillTimers[__instance.PlayerId] > 0: - Main.MedusaBodies.Remove(target.PlayerId); - Main.MedusaBodies.Add(target.PlayerId); - __instance.Notify(GetString("MedusaStoneBody")); - __instance.SetKillCooldown(Medusa.KillCooldownAfterStoneGazing.GetFloat()); - Logger.Info($"{__instance.GetRealName()} stoned {target.PlayerName}'s body", "Medusa"); - return false; - } - if (Main.PlayerStates[target.PlayerId].deathReason == PlayerState.DeathReason.Gambled || killerRole == CustomRoles.Scavenger || Main.CleanerBodies.Contains(target.PlayerId) @@ -1299,13 +732,13 @@ class ReportDeadBodyPatch if (__instance.Is(CustomRoles.Oblivious)) { - if (!tpc.Is(CustomRoles.Bait) || (tpc.Is(CustomRoles.Bait) && Options.ObliviousBaitImmune.GetBool())) /* && (target?.Object != null)*/ + if (!tpc.Is(CustomRoles.Bait) || Options.ObliviousBaitImmune.GetBool()) /* && (target?.Object != null)*/ { return false; } } - if (__instance.Is(CustomRoles.Unlucky) && (target?.Object == null || !target.Object.Is(CustomRoles.Bait))) + if (__instance.Is(CustomRoles.Unlucky) && (target.Object == null || !target.Object.Is(CustomRoles.Bait))) { var Ue = IRandom.Instance; if (Ue.Next(0, 100) < Options.UnluckyReportSuicideChance.GetInt()) @@ -1315,7 +748,7 @@ class ReportDeadBodyPatch } } - if (Main.BoobyTrapBody.Contains(target.PlayerId) && __instance.IsAlive()) + if (BoobyTrap.BoobyTrapBody.Contains(target.PlayerId) && __instance.IsAlive()) { if (!Options.TrapOnlyWorksOnTheBodyBoobyTrap.GetBool()) { @@ -1324,7 +757,7 @@ class ReportDeadBodyPatch __instance.Suicide(PlayerState.DeathReason.Bombed, GetPlayerById(killerID)); RPC.PlaySoundRPC(killerID, Sounds.KillSound); - if (!Main.BoobyTrapBody.Contains(__instance.PlayerId)) Main.BoobyTrapBody.Add(__instance.PlayerId); + if (!BoobyTrap.BoobyTrapBody.Contains(__instance.PlayerId)) BoobyTrap.BoobyTrapBody.Add(__instance.PlayerId); BoobyTrap.KillerOfBoobyTrapBody.TryAdd(__instance.PlayerId, killerID); return false; } @@ -1409,21 +842,19 @@ class ReportDeadBodyPatch Main.LastVotedPlayerInfo = null; Witness.AllKillers.Clear(); Main.ArsonistTimer.Clear(); - if (Farseer.isEnable) Farseer.FarseerTimer.Clear(); + Farseer.FarseerTimer.Clear(); Puppeteer.PuppeteerList.Clear(); Puppeteer.PuppeteerDelayList.Clear(); Main.TaglockedList.Clear(); Main.GuesserGuessed.Clear(); Main.VeteranInProtect.Clear(); - Main.GrenadierBlinding.Clear(); - Main.Lighter.Clear(); + Grenadier.GrenadierBlinding.Clear(); Main.BlockSabo.Clear(); Main.BlockedVents.Clear(); Grenadier.MadGrenadierBlinding.Clear(); - if (Divinator.IsEnable) Divinator.didVote.Clear(); - if (Oracle.IsEnable) Oracle.didVote.Clear(); - if (Bloodhound.IsEnable) Bloodhound.Clear(); - if (Vulture.IsEnable) Vulture.Clear(); + Divinator.didVote.Clear(); + Oracle.didVote.Clear(); + Vulture.Clear(); foreach (var state in Main.PlayerStates.Values) { @@ -1446,17 +877,6 @@ class ReportDeadBodyPatch Stressed.OnMeetingStart(); - if (Math.Abs(Options.InhibitorCDAfterMeetings.GetFloat() - Options.InhibitorCD.GetFloat()) > 0.5f || Math.Abs(Options.SaboteurCD.GetFloat() - Options.SaboteurCDAfterMeetings.GetFloat()) > 0.5f) - { - foreach (PlayerControl x in Main.AllAlivePlayerControls) - { - if (x.Is(CustomRoles.Saboteur)) - { - Main.AllPlayerKillCooldown[x.PlayerId] = Options.SaboteurCDAfterMeetings.GetFloat(); - } - } - } - foreach (var pc in Main.AllPlayerControls) { if (Main.CheckShapeshift.ContainsKey(pc.PlayerId) && !Doppelganger.DoppelVictim.ContainsKey(pc.PlayerId)) @@ -1472,15 +892,6 @@ class ReportDeadBodyPatch _ = new LateTask(SyncAllSettings, 3f, "SyncAllSettings on meeting start"); } - - public static async void ChangeLocalNameAndRevert(string name, int time) - { - //It can't be helped because async Task gives a warning. - var revertName = PlayerControl.LocalPlayer.name; - PlayerControl.LocalPlayer.RpcSetNameEx(name); - await Task.Delay(time); - PlayerControl.LocalPlayer.RpcSetNameEx(revertName); - } } [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))] @@ -1556,7 +967,6 @@ class FixedUpdatePatch else BufferTime[playerId] = 10; } - if (Sniper.IsEnable) Sniper.OnFixedUpdate(player); if (!lowLoad) { Zoom.OnFixedUpdate(); @@ -1610,88 +1020,6 @@ class FixedUpdatePatch s.Role.OnFixedUpdate(player); } - switch (player.GetCustomRole()) - { - case CustomRoles.Vampire: - Vampire.OnFixedUpdate(player); - break; - case CustomRoles.Poisoner: - Poisoner.OnFixedUpdate(player); - break; - case CustomRoles.BountyHunter: - BountyHunter.FixedUpdate(player); - break; - case CustomRoles.SoulHunter when !lowLoad: - SoulHunter.OnFixedUpdate(); - break; - case CustomRoles.Glitch when !lowLoad: - Glitch.UpdateHackCooldown(player); - break; - case CustomRoles.Aid when !lowLoad: - Aid.OnFixedUpdate(player); - break; - case CustomRoles.Spy when !lowLoad: - Spy.OnFixedUpdate(player); - break; - case CustomRoles.RiftMaker when !lowLoad: - RiftMaker.OnFixedUpdate(player); - break; - case CustomRoles.Mastermind when !lowLoad: - Mastermind.OnFixedUpdate(); - break; - case CustomRoles.Magician when !lowLoad: - Magician.OnFixedUpdate(player); - break; - case CustomRoles.Mafioso when !lowLoad: - Mafioso.OnFixedUpdate(player); - break; - case CustomRoles.Librarian when !lowLoad: - Librarian.OnFixedUpdate(); - break; - case CustomRoles.NiceHacker when !lowLoad: - NiceHacker.OnFixedUpdate(player); - break; - case CustomRoles.Enderman when !lowLoad: - Enderman.OnFixedUpdate(); - break; - case CustomRoles.Bubble when !lowLoad: - Bubble.OnFixedUpdate(); - break; - case CustomRoles.Sentinel when !lowLoad: - Sentinel.OnFixedUpdate(); - break; - case CustomRoles.Analyzer: - Analyzer.OnFixedUpdate(player); - break; - case CustomRoles.SerialKiller: - SerialKiller.FixedUpdate(player); - break; - case CustomRoles.Penguin: - Penguin.OnFixedUpdate(); - break; - case CustomRoles.Benefactor when !lowLoad: - Benefactor.OnFixedUpdate(player); - break; - case CustomRoles.Chronomancer when !lowLoad: - Chronomancer.OnFixedUpdate(player); - break; - case CustomRoles.Druid when !lowLoad: - Druid.OnFixedUpdate(); - break; - case CustomRoles.Stealth when !lowLoad: - Stealth.OnFixedUpdate(player); - break; - case CustomRoles.Gambler when !lowLoad: - Gambler.OnFixedUpdate(player); - break; - case CustomRoles.Swiftclaw when !lowLoad: - Swiftclaw.OnFixedUpdate(player); - break; - case CustomRoles.Randomizer: - Randomizer.OnFixedUpdateForRandomizer(player, lowLoad); - break; - } - if (GameStates.IsInTask && player.Is(CustomRoles.PlagueBearer) && PlagueBearer.IsPlaguedAll(player)) { player.RpcSetCustomRole(CustomRoles.Pestilence); @@ -1701,7 +1029,6 @@ class FixedUpdatePatch PlagueBearer.PestilenceList.Add(playerId); player.ResetKillCooldown(); PlagueBearer.playerIdList.Remove(playerId); - player.SyncSettings(); } if (GameStates.IsInTask && player != null && player.IsAlive()) @@ -1714,15 +1041,7 @@ class FixedUpdatePatch } } - Druid.OnCheckPlayerPosition(player); - Sentinel.OnCheckPlayerPosition(player); - Tornado.OnCheckPlayerPosition(player); - BallLightning.OnCheckPlayerPosition(player); - Sprayer.OnCheckPlayerPosition(player); Asthmatic.OnCheckPlayerPosition(player); - PlagueDoctor.OnCheckPlayerPosition(player); - Beacon.OnCheckPlayerPosition(player); - Randomizer.OnCheckPlayerPosition(player); } if (!lowLoad && Main.PlayerStates.TryGetValue(playerId, out var playerState) && GameStates.IsInTask) @@ -1755,22 +1074,11 @@ class FixedUpdatePatch { if (state.Role.IsEnable) { - state.Role.OnGlobalFixedUpdate(); + state.Role.OnGlobalFixedUpdate(player); } } - YinYanger.OnFixedUpdate(); - Duellist.OnFixedUpdate(); - Kamikaze.OnFixedUpdate(); - Succubus.OnFixedUpdate(); - Necromancer.OnFixedUpdate(); - - if (Randomizer.IsEnable) - { - Sentinel.OnFixedUpdate(); - Randomizer.OnFixedUpdateForPlayers(player); - Randomizer.GlobalFixedUpdate(); - } + Randomizer.OnFixedUpdateForPlayers(player); } } @@ -1850,10 +1158,6 @@ class FixedUpdatePatch #endregion - if (Farseer.isEnable) Farseer.OnPostFix(player); - if (Addict.IsEnable) Addict.FixedUpdate(player); - if (Deathpact.IsEnable) Deathpact.OnFixedUpdate(player); - if (!lowLoad) { long now = TimeStamp; @@ -1864,7 +1168,12 @@ class FixedUpdatePatch { LastAddAbilityTime = now; - if (player.Is(CustomRoles.SabotageMaster)) SabotageMaster.UsedSkillCount -= SabotageMaster.AbilityChargesWhenFinishedTasks.GetFloat(); + if (player.Is(CustomRoles.SabotageMaster)) + { + var sm = Main.PlayerStates[playerId].Role as SabotageMaster; + sm.UsedSkillCount -= SabotageMaster.AbilityChargesWhenFinishedTasks.GetFloat(); + sm.SendRPC(); + } else { float add = player.GetCustomRole() switch @@ -1896,63 +1205,10 @@ class FixedUpdatePatch CustomRoles.Tracker => Tracker.AbilityChargesWhenFinishedTasks.GetFloat(), _ => float.MaxValue, }; - if (add != float.MaxValue && add > 0) player.RpcIncreaseAbilityUseLimitBy(add); + if (Math.Abs(add - float.MaxValue) > 0.5f && add > 0) player.RpcIncreaseAbilityUseLimitBy(add); } } - switch (player.GetCustomRole()) - { - case CustomRoles.Express when GameStates.IsInTask: - Express.OnFixedUpdate(player); - break; - - case CustomRoles.Vulture when Vulture.BodyReportCount[playerId] >= Vulture.NumberOfReportsToWin.GetInt() && GameStates.IsInTask: - Vulture.BodyReportCount[playerId] = Vulture.NumberOfReportsToWin.GetInt(); - CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Vulture); - CustomWinnerHolder.WinnerIds.Add(playerId); - break; - - case CustomRoles.Pelican: - Pelican.OnFixedUpdate(); - break; - - case CustomRoles.Sapper: - Sapper.OnFixedUpdate(player); - break; - - case CustomRoles.Ignitor: - Ignitor.OnFixedUpdate(player); - break; - - case CustomRoles.Swooper: - Swooper.OnFixedUpdate(player); - break; - - case CustomRoles.Wraith: - Wraith.OnFixedUpdate(player); - break; - - case CustomRoles.Chameleon: - Chameleon.OnFixedUpdate(player); - break; - - case CustomRoles.Werewolf: - Werewolf.OnFixedUpdate(player); - break; - - case CustomRoles.Alchemist: - Alchemist.OnFixedUpdate( /*player*/); - break; - - case CustomRoles.BloodKnight: - BloodKnight.OnFixedUpdate(player); - break; - - case CustomRoles.Spiritcaller: - Spiritcaller.OnFixedUpdate(player); - break; - } - if (Witness.AllKillers.TryGetValue(playerId, out var ktime) && ktime + Options.WitnessTime.GetInt() < now) Witness.AllKillers.Remove(playerId); if (GameStates.IsInTask && player.IsAlive() && Options.LadderDeath.GetBool()) FallFromLadder.FixedUpdate(player); if (GameStates.IsInGame) LoversSuicide(); @@ -1963,11 +1219,9 @@ class FixedUpdatePatch #endregion - if (GameStates.IsInTask && player == PlayerControl.LocalPlayer) + if (GameStates.IsInTask && player == PlayerControl.LocalPlayer && Options.DisableDevices.GetBool()) { - if (Options.DisableDevices.GetBool()) DisableDevice.FixedUpdate(); - if (player.Is(CustomRoles.AntiAdminer)) AntiAdminer.FixedUpdate(); - if (player.Is(CustomRoles.Monitor)) Monitor.FixedUpdate(); + DisableDevice.FixedUpdate(); } if (GameStates.IsInGame && Main.RefixCooldownDelay <= 0) @@ -2060,15 +1314,13 @@ class FixedUpdatePatch var seer = PlayerControl.LocalPlayer; var target = __instance; - string RealName; // string SeerRealName; Mark.Clear(); Suffix.Clear(); //名前変更 - RealName = target.GetRealName(); + string RealName = target.GetRealName(); // SeerRealName = seer.GetRealName(); - //名前色変更処理 //自分自身の名前の色を変更 if (target.AmOwner && GameStates.IsInTask) @@ -2100,7 +1352,7 @@ class FixedUpdatePatch // Name Color Manager RealName = RealName.ApplyNameColorData(seer, target, false); - if (Marshall.IsEnable && seer.GetCustomRole().IsCrewmate() && seer.Is(CustomRoles.Madmate) && Marshall.MadmateCanFindMarshall) //seerがインポスター + if (seer.GetCustomRole().IsCrewmate() && seer.Is(CustomRoles.Madmate) && Marshall.MadmateCanFindMarshall) //seerがインポスター { if (target.Is(CustomRoles.Marshall) && target.GetTaskState().IsTaskFinished) //targetがタスクを終わらせたマッドスニッチ Mark.Append(ColorString(GetRoleColor(CustomRoles.Marshall), "★")); //targetにマーク付与 @@ -2176,14 +1428,14 @@ class FixedUpdatePatch break; case CustomRoles.Analyzer: - if (Analyzer.CurrentTarget.ID == target.PlayerId) + if ((Main.PlayerStates[seer.PlayerId].Role as Analyzer).CurrentTarget.ID == target.PlayerId) { Mark.Append($"○"); } break; case CustomRoles.Puppeteer: - if (Main.PuppeteerList.ContainsValue(seer.PlayerId) && Main.PuppeteerList.ContainsKey(target.PlayerId)) + if (Puppeteer.PuppeteerList.ContainsValue(seer.PlayerId) && Puppeteer.PuppeteerList.ContainsKey(target.PlayerId)) { Mark.Append($"◆"); } @@ -2197,7 +1449,7 @@ class FixedUpdatePatch Suffix.Append(Tracker.GetTrackerArrow(seer, target)); break; case CustomRoles.AntiAdminer when GameStates.IsInTask: - AntiAdminer.FixedUpdate(); + (Main.PlayerStates[seer.PlayerId].Role as AntiAdminer).OnFixedUpdate(seer); if (target.AmOwner) { if (AntiAdminer.IsAdminWatch) Suffix.Append(GetString("AntiAdminerAD")); @@ -2206,17 +1458,6 @@ class FixedUpdatePatch if (AntiAdminer.IsCameraWatch) Suffix.Append(GetString("AntiAdminerCA")); } - break; - case CustomRoles.Monitor when GameStates.IsInTask: - Monitor.FixedUpdate(); - if (target.AmOwner) - { - if (Monitor.IsAdminWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("AdminWarning"))); - if (Monitor.IsVitalWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("VitalsWarning"))); - if (Monitor.IsDoorLogWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("DoorlogWarning"))); - if (Monitor.IsCameraWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("CameraWarning"))); - } - break; case CustomRoles.Executioner: Mark.Append(Executioner.TargetMark(seer, target)); @@ -2241,15 +1482,16 @@ class FixedUpdatePatch break; } - if (Totocalcio.IsEnable) Mark.Append(Totocalcio.TargetMark(seer, target)); - if (Romantic.IsEnable || VengefulRomantic.IsEnable || RuthlessRomantic.IsEnable) Mark.Append(Romantic.TargetMark(seer, target)); - if (Lawyer.IsEnable()) Mark.Append(Lawyer.LawyerMark(seer, target)); - if (Randomizer.IsEnable && Randomizer.IsShielded(target)) Mark.Append(ColorString(GetRoleColor(CustomRoles.Randomizer), "✚")); - if (Sniper.IsEnable && target.AmOwner) Mark.Append(Sniper.GetShotNotify(target.PlayerId)); - if (BallLightning.IsGhost(target) && BallLightning.IsEnable) Mark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■")); - if (Marshall.IsEnable) Mark.Append(Marshall.GetWarningMark(seer, target)); + Mark.Append(Totocalcio.TargetMark(seer, target)); + Mark.Append(Romantic.TargetMark(seer, target)); + Mark.Append(Lawyer.LawyerMark(seer, target)); + Mark.Append(Marshall.GetWarningMark(seer, target)); - if (Medic.IsEnable) + if (Randomizer.IsShielded(target)) Mark.Append(ColorString(GetRoleColor(CustomRoles.Randomizer), "✚")); + if (target.AmOwner) Mark.Append(Sniper.GetShotNotify(target.PlayerId)); + if (BallLightning.IsGhost(target)) Mark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■")); + + if (Medic.ProtectList.Count > 0) { var shieldMark = $" ●"; @@ -2266,11 +1508,8 @@ class FixedUpdatePatch Mark.Append(shieldMark); } - if (Snitch.IsEnable) - { - Mark.Append(Snitch.GetWarningArrow(seer, target)); - Mark.Append(Snitch.GetWarningMark(seer, target)); - } + Mark.Append(Snitch.GetWarningArrow(seer, target)); + Mark.Append(Snitch.GetWarningMark(seer, target)); if (Main.LoversPlayers.Count > 0) { @@ -2287,14 +1526,10 @@ class FixedUpdatePatch } } - if (Bubble.IsEnable) Suffix.Append(Bubble.GetEncasedPlayerSuffix(target)); - if (Randomizer.IsEnable) Suffix.Append(Randomizer.GetSuffixText(seer, target)); - - if (Deathpact.IsEnable) - { - Suffix.Append(Deathpact.GetDeathpactPlayerArrow(seer, target)); - Suffix.Append(Deathpact.GetDeathpactMark(seer, target)); - } + Suffix.Append(Bubble.GetEncasedPlayerSuffix(target)); + Suffix.Append(Randomizer.GetSuffixText(seer, target)); + Suffix.Append(Deathpact.GetDeathpactPlayerArrow(seer, target)); + Suffix.Append(Deathpact.GetDeathpactMark(seer, target)); if (seer.PlayerId == target.PlayerId) { @@ -2312,14 +1547,14 @@ class FixedUpdatePatch Suffix.Append(Ricochet.TargetText(seer.PlayerId)); break; case CustomRoles.Hitman: - Suffix.Append(Hitman.GetTargetText()); + Suffix.Append(Hitman.GetTargetText(seer.PlayerId)); break; } } if (target.Is(CustomRoles.Librarian)) Suffix.Append(Librarian.GetNameTextForSuffix(target.PlayerId)); - if (Spiritualist.IsEnable) Suffix.Append(Spiritualist.GetSpiritualistArrow(seer, target)); + Suffix.Append(Spiritualist.GetSpiritualistArrow(seer, target)); switch (Options.CurrentGameMode) { @@ -2335,10 +1570,10 @@ class FixedUpdatePatch break; } - if (Vulture.ArrowsPointingToDeadBody.GetBool() && Vulture.IsEnable) + if (Vulture.ArrowsPointingToDeadBody.GetBool()) Suffix.Append(Vulture.GetTargetArrow(seer, target)); - if (Tracefinder.IsEnable) Suffix.Append(Tracefinder.GetTargetArrow(seer, target)); + Suffix.Append(Tracefinder.GetTargetArrow(seer, target)); if (Options.CurrentGameMode == CustomGameMode.SoloKombat) Suffix.Append(SoloKombatManager.GetDisplayHealth(target)); @@ -2348,7 +1583,7 @@ class FixedUpdatePatch }*/ //Devourer - if (Devourer.HideNameOfConsumedPlayer.GetBool() && Devourer.PlayerSkinsCosumed.Any(a => a.Value.Contains(target.PlayerId))) + 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"); // Camouflage @@ -2360,14 +1595,14 @@ class FixedUpdatePatch var currentText = target.cosmetics.nameText.text; var changeTo = $"{RealName}{DeathReason}{Mark}"; - var needUpdate = false; - if (currentText != changeTo) needUpdate = true; + bool needUpdate = currentText != changeTo; if (needUpdate) { target.cosmetics.nameText.text = changeTo; float offset = 0.2f; + if (NameNotifyManager.Notice.TryGetValue(seer.PlayerId, out var notify) && notify.TEXT.Contains('\n')) { offset += 0.1f; @@ -2418,9 +1653,8 @@ class FixedUpdatePatch { if (!loversPlayer.Data.IsDead && loversPlayer.PlayerId != deathId) continue; Main.isLoversDead = true; - for (int i1 = 0; i1 < Main.LoversPlayers.Count; i1++) + foreach (var partnerPlayer in Main.LoversPlayers) { - PlayerControl partnerPlayer = Main.LoversPlayers[i1]; if (loversPlayer.PlayerId == partnerPlayer.PlayerId) continue; if (partnerPlayer.PlayerId != deathId && !partnerPlayer.Data.IsDead) { @@ -2478,6 +1712,8 @@ class ExitVentPatch Drainer.OnAnyoneExitVent(pc); + Main.PlayerStates[pc.PlayerId].Role.OnExitVent(pc, __instance); + if (Options.WhackAMole.GetBool()) { _ = new LateTask(() => { pc.TPtoRndVent(); }, 0.5f, "Whack-A-Mole TP"); @@ -2535,103 +1771,7 @@ class EnterVentPatch Damocles.OnEnterVent(pc.PlayerId, __instance.Id); } - switch (pc.GetCustomRole()) - { - case CustomRoles.Swooper: - Swooper.OnEnterVent(pc, __instance); - break; - case CustomRoles.Wraith: - Wraith.OnEnterVent(pc, __instance); - break; - case CustomRoles.Addict: - Addict.OnEnterVent(pc /*, __instance*/); - break; - case CustomRoles.CameraMan when !Options.UsePets.GetBool(): - CameraMan.OnEnterVent(pc); - break; - case CustomRoles.Alchemist: - Alchemist.OnEnterVent(pc, __instance.Id); - break; - case CustomRoles.Chameleon: - Chameleon.OnEnterVent(pc, __instance); - break; - case CustomRoles.Tether when !Options.UsePets.GetBool(): - Tether.OnEnterVent(pc, __instance.Id); - break; - case CustomRoles.Werewolf: - Werewolf.OnEnterVent(pc); - break; - case CustomRoles.Mafioso: - Mafioso.OnEnterVent(__instance.Id); - break; - case CustomRoles.Lurker: - Lurker.OnEnterVent(pc); - break; - case CustomRoles.Druid when !Options.UsePets.GetBool(): - Druid.OnEnterVent(pc); - break; - case CustomRoles.Doormaster when !Options.UsePets.GetBool(): - Doormaster.OnEnterVent(pc); - break; - case CustomRoles.Hookshot: - Hookshot.SwitchActionMode(); - break; - case CustomRoles.Sentinel when !Options.UsePets.GetBool(): - Sentinel.StartPatrolling(pc); - break; - case CustomRoles.Veteran when !Options.UsePets.GetBool(): - if (pc.GetAbilityUseLimit() >= 1) - { - Main.VeteranInProtect.Remove(pc.PlayerId); - Main.VeteranInProtect.Add(pc.PlayerId, GetTimeStamp(DateTime.Now)); - pc.RpcRemoveAbilityUse(); - //pc.RpcGuardAndKill(pc); - pc.RPCPlayCustomSound("Gunload"); - pc.Notify(GetString("VeteranOnGuard"), Options.VeteranSkillDuration.GetFloat()); - pc.AddAbilityCD(); - pc.MarkDirtySettings(); - } - else - { - pc.Notify(GetString("OutOfAbilityUsesDoMoreTasks")); - } - - break; - case CustomRoles.DovesOfNeace when !Options.UsePets.GetBool(): - if (pc.GetAbilityUseLimit() < 1) - { - //pc?.MyPhysics?.RpcBootFromVent(__instance.Id); - pc.Notify(GetString("OutOfAbilityUsesDoMoreTasks")); - } - else - { - pc.RpcRemoveAbilityUse(); - //pc.RpcGuardAndKill(pc); - Main.AllAlivePlayerControls.Where(x => - pc.Is(CustomRoles.Madmate) ? x.CanUseKillButton() && x.GetCustomRole().IsCrewmate() : x.CanUseKillButton() - ).Do(x => - { - x.RPCPlayCustomSound("Dove"); - x.ResetKillCooldown(); - x.SetKillCooldown(); - if (x.Is(CustomRoles.SerialKiller)) - { - SerialKiller.OnReportDeadBody(); - } - - x.Notify(ColorString(GetRoleColor(CustomRoles.DovesOfNeace), GetString("DovesOfNeaceSkillNotify"))); - }); - pc.RPCPlayCustomSound("Dove"); - pc.Notify(string.Format(GetString("DovesOfNeaceOnGuard"), pc.GetAbilityUseLimit())); - pc.AddAbilityCD(); - } - - break; - - case CustomRoles.Perceiver when !Options.UsePets.GetBool(): - Perceiver.UseAbility(pc); - break; - } + Main.PlayerStates[pc.PlayerId].Role.OnEnterVent(pc, __instance); } } @@ -2652,7 +1792,7 @@ class CoEnterVentPatch switch (Options.CurrentGameMode) { case CustomGameMode.FFA when FFAManager.FFA_DisableVentingWhenTwoPlayersAlive.GetBool() && Main.AllAlivePlayerControls.Length <= 2: - var pc = __instance?.myPlayer; + var pc = __instance.myPlayer; _ = new LateTask(() => { pc?.Notify(GetString("FFA-NoVentingBecauseTwoPlayers"), 7f); @@ -2729,16 +1869,11 @@ class CoEnterVentPatch _ = new LateTask(() => { __instance.RpcBootFromVent(id); }, 0.5f); } - //处理弹出管道的阻塞 - if (Main.NormalOptions.MapId == (int)MapNames.Dleks || ((__instance.myPlayer.Data.Role.Role != RoleTypes.Engineer && //不是工程师 - !__instance.myPlayer.CanUseImpostorVentButton()) || //不能使用内鬼的跳管按钮 + if (Main.NormalOptions.MapId == (int)MapNames.Dleks || ((__instance.myPlayer.Data.Role.Role != RoleTypes.Engineer && + !__instance.myPlayer.CanUseImpostorVentButton()) || (__instance.myPlayer.Is(CustomRoles.Mayor) && Main.MayorUsedButtonCount.TryGetValue(__instance.myPlayer.PlayerId, out var count) && count >= Options.MayorNumOfUseButton.GetInt()) || (__instance.myPlayer.Is(CustomRoles.Paranoia) && Main.ParaUsedButtonCount.TryGetValue(__instance.myPlayer.PlayerId, out var count2) && count2 >= Options.ParanoiaNumOfUseButton.GetInt())) - && !__instance.myPlayer.Is(CustomRoles.Nimble) - //(__instance.myPlayer.Is(CustomRoles.Veteran) && Main.VeteranNumOfUsed.TryGetValue(__instance.myPlayer.PlayerId, out var count3) && count3 < 1) || - //(__instance.myPlayer.Is(CustomRoles.Grenadier) && Main.GrenadierNumOfUsed.TryGetValue(__instance.myPlayer.PlayerId, out var count4) && count4 < 1) || - //(__instance.myPlayer.Is(CustomRoles.DovesOfNeace) && Main.DovesOfNeaceNumOfUsed.TryGetValue(__instance.myPlayer.PlayerId, out var count5) && count5 < 1) - ) + && !__instance.myPlayer.Is(CustomRoles.Nimble)) { try { @@ -2766,37 +1901,7 @@ class CoEnterVentPatch return true; } - switch (__instance.myPlayer.GetCustomRole()) - { - case CustomRoles.Swooper: - Swooper.OnCoEnterVent(__instance, id); - break; - case CustomRoles.Wraith: - Wraith.OnCoEnterVent(__instance, id); - break; - case CustomRoles.Chameleon: - Chameleon.OnCoEnterVent(__instance, id); - break; - case CustomRoles.Mole: - Mole.OnCoEnterVent(__instance); - break; - case CustomRoles.Alchemist when Alchemist.PotionID == 6: - Alchemist.OnCoEnterVent(__instance, id); - break; - case CustomRoles.RiftMaker: - RiftMaker.OnEnterVent(__instance.myPlayer, id); - break; - case CustomRoles.WeaponMaster: - WeaponMaster.OnEnterVent(__instance.myPlayer, id); - break; - case CustomRoles.Convener: - Convener.UseAbility(__instance.myPlayer, id); - break; - } - - //if (__instance.myPlayer.Is(CustomRoles.DovesOfNeace)) __instance.myPlayer.Notify(GetString("DovesOfNeaceMaxUsage")); - //if (__instance.myPlayer.Is(CustomRoles.Veteran)) __instance.myPlayer.Notify(GetString("OutOfAbilityUsesDoMoreTasks")); - //if (__instance.myPlayer.Is(CustomRoles.Grenadier)) __instance.myPlayer.Notify(GetString("OutOfAbilityUsesDoMoreTasks")); + Main.PlayerStates[__instance.myPlayer.PlayerId].Role.OnCoEnterVent(__instance, id); return true; } @@ -2832,6 +1937,8 @@ class PlayerControlCompleteTaskPatch { if (__instance != null && __instance.IsAlive()) Benefactor.OnTaskComplete(__instance, __instance.myTasks[(Index)Convert.ToInt32(idx)] as PlayerTask); + if (__instance == null) return; + Snitch.OnCompleteTask(__instance); var isTaskFinish = __instance.GetTaskState().IsTaskFinished; @@ -2957,7 +2064,7 @@ class PlayerControlSetRolePatch } else { - foreach ((var seer, var role) in ghostRoles) + foreach ((PlayerControl seer, RoleTypes role) in ghostRoles) { Logger.Info($"Desync {targetName} => {role} for {seer.GetNameWithRole().RemoveHtmlTags()}", "PlayerControl.RpcSetRole"); target.RpcSetRoleDesync(role, seer.GetClientId()); diff --git a/Patches/PlayerJoinAndLeftPatch.cs b/Patches/PlayerJoinAndLeftPatch.cs index 0f27ad629..5076ced92 100644 --- a/Patches/PlayerJoinAndLeftPatch.cs +++ b/Patches/PlayerJoinAndLeftPatch.cs @@ -1,10 +1,10 @@ -using System; -using System.Text.RegularExpressions; -using System.Threading.Tasks; using AmongUs.Data; using AmongUs.GameOptions; using HarmonyLib; using InnerNet; +using System; +using System.Text.RegularExpressions; +using System.Threading.Tasks; using TOHE.Modules; using TOHE.Roles.Crewmate; using TOHE.Roles.Neutral; @@ -53,6 +53,7 @@ class OnGameJoinedPatch AmongUsClient.Instance.ExitGame(DisconnectReasons.Banned); SceneChanger.ChangeScene("MainMenu"); } + var client = PlayerControl.LocalPlayer.GetClient(); Logger.Info($"{client.PlayerName.RemoveHtmlTags()} (ClientID: {client.Id} / FriendCode: {client.FriendCode} / HashPuid: {client.GetHashedPuid()} / Platform: {client.PlatformData.Platform}) Hosted room", "Session"); }, 1f, "OnGameJoinedPatch"); @@ -62,10 +63,11 @@ class OnGameJoinedPatch } } } + [HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.DisconnectInternal))] class DisconnectInternalPatch { - public static void Prefix(/*InnerNetClient __instance,*/ DisconnectReasons reason, string stringReason) + public static void Prefix( /*InnerNetClient __instance,*/ DisconnectReasons reason, string stringReason) { ShowDisconnectPopupPatch.Reason = reason; ShowDisconnectPopupPatch.StringReason = stringReason; @@ -75,10 +77,11 @@ class DisconnectInternalPatch Cloud.StopConnect(); } } + [HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnPlayerJoined))] class OnPlayerJoinedPatch { - public static void Postfix(/*AmongUsClient __instance,*/ [HarmonyArgument(0)] ClientData client) + public static void Postfix( /*AmongUsClient __instance,*/ [HarmonyArgument(0)] ClientData client) { Logger.Info($"{client.PlayerName} (ClientID: {client.Id} / FriendCode: {client.FriendCode}) joined the lobby", "Session"); if (AmongUsClient.Instance.AmHost && client.FriendCode == "" && Options.KickPlayerFriendCodeNotExist.GetBool() && !GameStates.IsLocalGame) @@ -89,6 +92,7 @@ class OnPlayerJoinedPatch Logger.SendInGame(string.Format(GetString("Message.KickedByNoFriendCode"), client.PlayerName)); Logger.Info($"TempBanned a player {client?.PlayerName} without a friend code", "Temp Ban"); } + if (AmongUsClient.Instance.AmHost && client.PlatformData.Platform == (Platforms.Android | Platforms.IPhone) && Options.KickAndroidPlayer.GetBool()) { AmongUsClient.Instance?.KickPlayer(client.Id, false); @@ -96,16 +100,19 @@ class OnPlayerJoinedPatch Logger.SendInGame(msg); Logger.Info(msg, "Android Kick"); } + if (AmongUsClient.Instance.AmHost && client.PlayerName.Contains("Silasticm", StringComparison.OrdinalIgnoreCase)) { AmongUsClient.Instance?.KickPlayer(client.Id, false); Logger.SendInGame("They were probably hacking tbh"); } + if (DestroyableSingleton.Instance.IsPlayerBlockedUsername(client.FriendCode) && AmongUsClient.Instance.AmHost) { AmongUsClient.Instance?.KickPlayer(client.Id, true); Logger.Info($"Ban Player ー {client?.PlayerName}({client.FriendCode}) has been banned.", "BAN"); } + BanManager.CheckBanPlayer(client); BanManager.CheckDenyNamePlayer(client); RPC.RpcVersionCheck(); @@ -117,6 +124,7 @@ class OnPlayerJoinedPatch } } } + [HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.OnPlayerLeft))] class OnPlayerLeftPatch { @@ -227,17 +235,20 @@ class OnPlayerLeftPatch data.Character.Data.Disconnected = true; } - catch (NullReferenceException) { } + catch (NullReferenceException) + { + } catch (Exception ex) { Logger.Error(ex.ToString(), "OnPlayerLeftPatch.Postfix"); } } } + [HarmonyPatch(typeof(AmongUsClient), nameof(AmongUsClient.CreatePlayer))] class CreatePlayerPatch { - public static void Postfix(/*AmongUsClient __instance,*/ [HarmonyArgument(0)] ClientData client) + public static void Postfix( /*AmongUsClient __instance,*/ [HarmonyArgument(0)] ClientData client) { if (!AmongUsClient.Instance.AmHost) return; @@ -254,6 +265,7 @@ class CreatePlayerPatch if (Options.DisableEmojiName.GetBool()) name = Regex.Replace(name, @"\p{Cs}", string.Empty); if (Regex.Replace(Regex.Replace(name, @"\s", string.Empty), @"[\x01-\x1F,\x7F]", string.Empty).Length < 1) name = Main.Get_TName_Snacks; } + Main.AllPlayerNames.Remove(client.Character.PlayerId); Main.AllPlayerNames.TryAdd(client.Character.PlayerId, name); if (!name.Equals(client.PlayerName)) @@ -266,7 +278,11 @@ class CreatePlayerPatch }, 1f, "Name Format"); } - _ = new LateTask(() => { if (client.Character == null || !GameStates.IsLobby) return; OptionItem.SyncAllOptions(client.Id); }, 3f, "Sync All Options For New Player"); + _ = new LateTask(() => + { + if (client.Character == null || !GameStates.IsLobby) return; + OptionItem.SyncAllOptions(client.Id); + }, 3f, "Sync All Options For New Player"); Main.GuessNumber[client.Character.PlayerId] = [-1, 7]; @@ -289,6 +305,7 @@ class CreatePlayerPatch } }, 1f, "DisplayKillLog"); } + if (Options.AutoDisplayLastRoles.GetBool()) { _ = new LateTask(() => @@ -300,6 +317,7 @@ class CreatePlayerPatch } }, 1.1f, "DisplayLastRoles"); } + if (Options.AutoDisplayLastResult.GetBool()) { _ = new LateTask(() => @@ -311,6 +329,7 @@ class CreatePlayerPatch } }, 1.2f, "DisplayLastResult"); } + if (PlayerControl.LocalPlayer.FriendCode.GetDevUser().IsUp && Options.EnableUpMode.GetBool()) { _ = new LateTask(() => diff --git a/Patches/RandomSpawnPatch.cs b/Patches/RandomSpawnPatch.cs index 9c9673178..2208e08eb 100644 --- a/Patches/RandomSpawnPatch.cs +++ b/Patches/RandomSpawnPatch.cs @@ -1,7 +1,7 @@ +using HarmonyLib; using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; using TOHE.Roles.Impostor; using UnityEngine; @@ -13,6 +13,7 @@ class RandomSpawn public class CustomNetworkTransformPatch { public static Dictionary NumOfTP = []; + public static void Postfix(CustomNetworkTransform __instance, [HarmonyArgument(0)] Vector2 position) { if (!AmongUsClient.Instance.AmHost) return; @@ -25,6 +26,7 @@ class RandomSpawn Logger.Warn("Player is null", "RandomSpawn"); return; } + if (player.Is(CustomRoles.GM)) return; NumOfTP[player.PlayerId]++; @@ -42,6 +44,7 @@ class RandomSpawn } } } + public static void TP(CustomNetworkTransform nt, Vector2 location) { //if (AmongUsClient.Instance.AmHost) nt.SnapTo(location); @@ -60,6 +63,7 @@ class RandomSpawn Logger.Info($"{player.Data.PlayerName} => {spawn.Key} {spawn.Value}", "RandomSpawn"); player.TP(spawn.Value, log: false); } + public abstract KeyValuePair GetLocation(); } @@ -82,11 +86,13 @@ class RandomSpawn ["Reactor"] = new(-20.5f, -5.5f), ["MedBay"] = new(-9.0f, -4.0f) }; + public override KeyValuePair GetLocation() { return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } + public class MiraHQSpawnMap : SpawnMap { public Dictionary positions = new() @@ -106,11 +112,13 @@ class RandomSpawn ["Office"] = new(15.0f, 19.0f), ["Greenhouse"] = new(17.8f, 23.0f) }; + public override KeyValuePair GetLocation() { return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } + public class PolusSpawnMap : SpawnMap { public Dictionary positions = new() @@ -131,19 +139,23 @@ class RandomSpawn ["Toilet"] = new(34.0f, -10.0f), ["SpecimenRoom"] = new(36.5f, -22.0f) }; + public override KeyValuePair GetLocation() { return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } + public class DleksSpawnMap : SpawnMap { public Dictionary positions = new SkeldSpawnMap().positions.ToDictionary(e => e.Key, e => new Vector2(-e.Value.x, e.Value.y)); + public override KeyValuePair GetLocation() { return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } + public class AirshipSpawnMap : SpawnMap { public Dictionary positions = new() @@ -168,6 +180,7 @@ class RandomSpawn ["Toilet"] = new(30.9f, 6.8f), ["Showers"] = new(21.2f, -0.8f) }; + public override KeyValuePair GetLocation() { return Options.AirshipAdditionalSpawn.GetBool() @@ -175,6 +188,7 @@ class RandomSpawn : positions.ToArray()[..6].OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } + public class FungleSpawnMap : SpawnMap { public Dictionary positions = new() @@ -198,6 +212,7 @@ class RandomSpawn ["UpperEngine"] = new(22.4f, 3.4f), ["Communications"] = new(22.2f, 13.7f) }; + public override KeyValuePair GetLocation() { return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); diff --git a/Patches/SabotageSystemPatch.cs b/Patches/SabotageSystemPatch.cs index 8c84798ad..abb353650 100644 --- a/Patches/SabotageSystemPatch.cs +++ b/Patches/SabotageSystemPatch.cs @@ -1,6 +1,6 @@ -using System.Linq; using HarmonyLib; using Hazel; +using System.Linq; namespace TOHE; diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs index 9eb923aaa..bc58bfb4c 100644 --- a/Patches/ShipStatusPatch.cs +++ b/Patches/ShipStatusPatch.cs @@ -1,8 +1,9 @@ -using System.Collections.Generic; -using System.Linq; using BepInEx; using HarmonyLib; using Hazel; +using System.Collections.Generic; +using System.Linq; +using TOHE.Patches; using TOHE.Roles.AddOns.Crewmate; using TOHE.Roles.AddOns.Impostor; using TOHE.Roles.Crewmate; @@ -15,7 +16,7 @@ namespace TOHE; [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.FixedUpdate))] class ShipFixedUpdatePatch { - public static void Postfix(/*ShipStatus __instance*/) + public static void Postfix( /*ShipStatus __instance*/) { if (!AmongUsClient.Instance.AmHost) return; if (Main.IsFixedCooldown && Main.RefixCooldownDelay >= 0) @@ -30,22 +31,38 @@ class ShipFixedUpdatePatch } } } + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.UpdateSystem), typeof(SystemTypes), typeof(PlayerControl), typeof(MessageReader))] public static class MessageReaderUpdateSystemPatch { public static void Prefix(ShipStatus __instance, [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, [HarmonyArgument(2)] MessageReader reader) { - try { RepairSystemPatch.Prefix(__instance, systemType, player, MessageReader.Get(reader).ReadByte()); } catch { } + try + { + RepairSystemPatch.Prefix(__instance, systemType, player, MessageReader.Get(reader).ReadByte()); + } + catch + { + } } - public static void Postfix(/*ShipStatus __instance,*/ [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, [HarmonyArgument(2)] MessageReader reader) + + public static void Postfix( /*ShipStatus __instance,*/ [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, [HarmonyArgument(2)] MessageReader reader) { - try { RepairSystemPatch.Postfix(/*__instance,*/ systemType, player, MessageReader.Get(reader).ReadByte()); } catch { } + try + { + RepairSystemPatch.Postfix( /*__instance,*/ systemType, player, MessageReader.Get(reader).ReadByte()); + } + catch + { + } } } + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.UpdateSystem), typeof(SystemTypes), typeof(PlayerControl), typeof(byte))] class RepairSystemPatch { public static bool IsComms; + public static bool Prefix(ShipStatus __instance, [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, @@ -66,9 +83,11 @@ class RepairSystemPatch //Note: "SystemTypes.Laboratory" сauses bugs in the Host, it is better not to use if (player.Is(CustomRoles.Fool) && (systemType is - SystemTypes.Comms or - SystemTypes.Electrical)) - { return false; } + SystemTypes.Comms or + SystemTypes.Electrical)) + { + return false; + } switch (player.GetCustomRole()) { @@ -107,41 +126,19 @@ class RepairSystemPatch return false; } - if (player.Is(CustomRoles.Mafioso)) Mafioso.OnSabotage(player); + Main.PlayerStates[player.PlayerId].Role.OnSabotage(player); + + if (player.Is(CustomRoleTypes.Impostor) && !player.IsAlive() && Options.DeadImpCantSabotage.GetBool()) return false; if (player.Is(CustomRoleTypes.Impostor) && (player.IsAlive() || !Options.DeadImpCantSabotage.GetBool()) && !player.Is(CustomRoles.Minimalism)) return true; - switch (player.GetCustomRole()) + return player.GetCustomRole() switch { - case CustomRoles.Glitch: - Glitch.Mimic(player); - return false; - case CustomRoles.Magician: - Magician.UseCard(player); - return false; - case CustomRoles.WeaponMaster: - WeaponMaster.SwitchMode(); - return false; - case CustomRoles.Enderman: - Enderman.MarkPosition(); - return false; - case CustomRoles.Hookshot: - Hookshot.ExecuteAction(); - return false; - case CustomRoles.Sprayer: - Sprayer.PlaceTrap(); - return false; - case CustomRoles.Jackal when Jackal.CanUseSabotage.GetBool(): - return true; - case CustomRoles.Sidekick when Jackal.CanUseSabotageSK.GetBool(): - return true; - case CustomRoles.Traitor when Traitor.CanUseSabotage.GetBool(): - return true; - case CustomRoles.Parasite when player.IsAlive(): - return true; - case CustomRoles.Refugee when player.IsAlive(): - return true; - default: - return Main.PlayerStates[player.PlayerId].Role.CanUseSabotage(player); - } + CustomRoles.Jackal when Jackal.CanSabotage.GetBool() => true, + CustomRoles.Sidekick when Jackal.CanSabotageSK.GetBool() => true, + CustomRoles.Traitor when Traitor.CanSabotage.GetBool() => true, + CustomRoles.Parasite when player.IsAlive() => true, + CustomRoles.Refugee when player.IsAlive() => true, + _ => Main.PlayerStates[player.PlayerId].Role.CanUseSabotage(player) + }; case SystemTypes.Security when amount == 1: var camerasDisabled = (MapNames)Main.NormalOptions.MapId switch { @@ -157,9 +154,11 @@ class RepairSystemPatch return !camerasDisabled; } + return true; } - public static void Postfix(/*ShipStatus __instance,*/ + + public static void Postfix( /*ShipStatus __instance,*/ [HarmonyArgument(0)] SystemTypes systemType, [HarmonyArgument(1)] PlayerControl player, [HarmonyArgument(2)] byte amount) @@ -187,9 +186,11 @@ class RepairSystemPatch Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player); break; } + if (player.Is(CustomRoles.Damocles) && Damocles.countRepairSabotage) Damocles.OnRepairSabotage(player.PlayerId); if (player.Is(CustomRoles.Stressed) && Stressed.countRepairSabotage) Stressed.OnRepairSabotage(player); } + break; case SystemTypes.Reactor: case SystemTypes.LifeSupp: @@ -202,6 +203,7 @@ class RepairSystemPatch break; } } + public static void CheckAndOpenDoorsRange(ShipStatus __instance, int amount, int min, int max) { var Ids = new List(); @@ -209,8 +211,10 @@ class RepairSystemPatch { Ids.Add(i); } + CheckAndOpenDoors(__instance, amount, [.. Ids]); } + private static void CheckAndOpenDoors(ShipStatus __instance, int amount, params int[] DoorIds) { if (!DoorIds.Contains(amount)) return; @@ -220,10 +224,11 @@ class RepairSystemPatch } } } + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.CloseDoorsOfType))] class CloseDoorsPatch { - public static bool Prefix(/*ShipStatus __instance, */[HarmonyArgument(0)] SystemTypes room) + public static bool Prefix( /*ShipStatus __instance, */ [HarmonyArgument(0)] SystemTypes room) { bool allow = !Options.DisableSabotage.GetBool() && Options.CurrentGameMode is not CustomGameMode.SoloKombat and not CustomGameMode.FFA and not CustomGameMode.MoveAndStop; @@ -234,6 +239,7 @@ class CloseDoorsPatch return allow; } } + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.Start))] class StartPatch { @@ -259,15 +265,17 @@ class StartPatch } } } + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.StartMeeting))] class StartMeetingPatch { - public static void Prefix(/*ShipStatus __instance, PlayerControl reporter,*/ GameData.PlayerInfo target) + public static void Prefix( /*ShipStatus __instance, PlayerControl reporter,*/ GameData.PlayerInfo target) { MeetingStates.ReportTarget = target; MeetingStates.DeadBodies = Object.FindObjectsOfType(); } } + [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.Begin))] class BeginPatch { @@ -278,6 +286,7 @@ class BeginPatch //Should I initialize the host role here? } } + [HarmonyPatch(typeof(GameManager), nameof(GameManager.CheckTaskCompletion))] class CheckTaskCompletionPatch { @@ -288,6 +297,7 @@ class CheckTaskCompletionPatch __result = false; return false; } + return true; } } \ No newline at end of file diff --git a/Patches/TaskAdderPatch.cs b/Patches/TaskAdderPatch.cs index cfb5d9e57..fea1f2692 100644 --- a/Patches/TaskAdderPatch.cs +++ b/Patches/TaskAdderPatch.cs @@ -1,8 +1,8 @@ +using AmongUs.GameOptions; +using HarmonyLib; using System; using System.Collections; using System.Linq; -using AmongUs.GameOptions; -using HarmonyLib; using UnityEngine; using Object = UnityEngine.Object; @@ -12,6 +12,7 @@ namespace TOHE; class ShowFolderPatch { private static TaskFolder CustomRolesFolder; + public static void Prefix(TaskAdderGame __instance, [HarmonyArgument(0)] TaskFolder taskFolder) { if (__instance.Root == taskFolder && CustomRolesFolder == null) @@ -26,6 +27,7 @@ class ShowFolderPatch __instance.Root.SubFolders.Add(rolesFolder); } } + public static void Postfix(TaskAdderGame __instance, [HarmonyArgument(0)] TaskFolder taskFolder) { Logger.Info("Opened " + taskFolder.FolderName, "TaskFolder"); @@ -82,10 +84,14 @@ class TaskAddButtonUpdatePatch __instance.Overlay.enabled = PlayerCustomRole == FileCustomRole; } } - catch { } + catch + { + } + return true; } } + [HarmonyPatch(typeof(TaskAddButton), nameof(TaskAddButton.AddTask))] class AddTaskButtonPatch { @@ -101,7 +107,10 @@ class AddTaskButtonPatch return false; } } - catch { } + catch + { + } + return true; } } \ No newline at end of file diff --git a/Patches/onGameStartedPatch.cs b/Patches/onGameStartedPatch.cs index aacee4631..7ff541df3 100644 --- a/Patches/onGameStartedPatch.cs +++ b/Patches/onGameStartedPatch.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; using AmongUs.GameOptions; using HarmonyLib; using Hazel; +using System; +using System.Collections.Generic; +using System.Linq; using TOHE.Modules; using TOHE.Roles.AddOns.Common; using TOHE.Roles.AddOns.Crewmate; @@ -159,6 +159,7 @@ internal class ChangeRoleSettings Main.LastNotifyNames[pair] = target.name; } } + foreach (PlayerControl pc in Main.AllPlayerControls) { var colorId = pc.Data.DefaultOutfit.ColorId; @@ -175,17 +176,18 @@ internal class ChangeRoleSettings Camouflage.PlayerSkins[pc.PlayerId] = new GameData.PlayerOutfit().Set(outfit.PlayerName, outfit.ColorId, outfit.HatId, outfit.SkinId, outfit.VisorId, outfit.PetId, outfit.NamePlateId); Main.clientIdList.Add(pc.GetClientId()); } + Main.VisibleTasksCount = true; if (__instance.AmHost) { RPC.SyncCustomSettingsRPC(); Main.RefixCooldownDelay = 0; } + FallFromLadder.Reset(); try { - BountyHunter.Init(); SerialKiller.Init(); EvilDiviner.Init(); @@ -388,6 +390,7 @@ internal class ChangeRoleSettings } } } + [HarmonyPatch(typeof(RoleManager), nameof(RoleManager.SelectRoles))] internal class SelectRolesPatch { @@ -403,6 +406,7 @@ internal class SelectRolesPatch { senders[pc.PlayerId] = new CustomRpcSender($"{pc.name}'s SetRole Sender", SendOption.Reliable, false).StartMessage(pc.GetClientId()); } + RpcSetRoleReplacer.StartReplace(senders); if (Options.EnableGM.GetBool()) @@ -435,7 +439,6 @@ internal class SelectRolesPatch MakeDesyncSender(senders, rolesMap); - } catch (Exception e) { @@ -465,6 +468,7 @@ internal class SelectRolesPatch { physicistSpawn = true; } + if (rd.Next(1, 100) <= (Options.CustomAdtRoleSpawnRate.TryGetValue(CustomRoles.Nimble, out var x2) ? x2.GetFloat() : 0) && CustomRoles.Nimble.IsEnable()) { nimbleSpawn = true; @@ -512,7 +516,8 @@ internal class SelectRolesPatch } if (nimbleSpawn) Main.NimblePlayer = nimbleList[rd.Next(0, nimbleList.Count)]; - if (physicistSpawn) while (Main.PhysicistPlayer == byte.MaxValue || Main.PhysicistPlayer == Main.NimblePlayer) + if (physicistSpawn) + while (Main.PhysicistPlayer == byte.MaxValue || Main.PhysicistPlayer == Main.NimblePlayer) Main.PhysicistPlayer = physicistList[rd.Next(0, physicistList.Count)]; List<(PlayerControl, RoleTypes)> newList = []; @@ -540,6 +545,7 @@ internal class SelectRolesPatch Logger.Warn($"{PLAYER.GetRealName()} was assigned Physicist, their role basis was changed to Scientist", "Physicist"); } } + if (Options.EveryoneCanVent.GetBool()) { if (roleType == RoleTypes.Crewmate || (roleType == RoleTypes.Scientist && Options.OverrideScientistBasedRoles.GetBool())) @@ -548,9 +554,11 @@ internal class SelectRolesPatch Logger.Info($"Everyone can vent => {PLAYER.GetRealName()}'s role was changed to Engineer", "SetRoleReplacer"); } } + newList.Add((PLAYER, roleType)); Logger.Warn(ROLETYPE == roleType ? $"Register original role type => {PLAYER.GetRealName()}: {ROLETYPE}" : $"Register original role type => {PLAYER.GetRealName()}: {ROLETYPE} => {roleType}", "Override Role Select"); } + if (Options.EnableGM.GetBool()) newList.Add((PlayerControl.LocalPlayer, RoleTypes.Crewmate)); RpcSetRoleReplacer.StoragedData = newList; @@ -615,7 +623,8 @@ internal class SelectRolesPatch foreach (CustomRoles role in AddonRolesList.ToArray()) { if (rd.Next(1, 100) <= (Options.CustomAdtRoleSpawnRate.TryGetValue(role, out var sc) ? sc.GetFloat() : 0)) - if (role.IsEnable()) AssignSubRoles(role); + if (role.IsEnable()) + AssignSubRoles(role); } //RPCによる同期 @@ -623,7 +632,7 @@ internal class SelectRolesPatch { ExtendedPlayerControl.RpcSetCustomRole(pair.Key, pair.Value.MainRole); - foreach (CustomRoles subRole in pair.Value.SubRoles.ToArray()) + foreach (CustomRoles subRole in pair.Value.SubRoles) { ExtendedPlayerControl.RpcSetCustomRole(pair.Key, subRole); } @@ -635,8 +644,6 @@ internal class SelectRolesPatch { if (pc.Data.Role.Role == RoleTypes.Shapeshifter) Main.CheckShapeshift.Add(pc.PlayerId, false); - - Utils.AddRoles(pc.PlayerId, pc.GetCustomRole()); } catch (Exception ex) { @@ -647,7 +654,7 @@ internal class SelectRolesPatch Stressed.Add(); Asthmatic.Add(); - EndOfSelectRolePatch: + EndOfSelectRolePatch: if (Options.CurrentGameMode == CustomGameMode.HotPotato) HotPotatoManager.OnGameStart(); @@ -721,6 +728,7 @@ internal class SelectRolesPatch Logger.Fatal(ex.ToString(), "Select Role Postfix"); } } + private static void AssignDesyncRole(CustomRoles role, PlayerControl player, Dictionary senders, Dictionary<(byte, byte), RoleTypes> rolesMap, RoleTypes BaseRole, RoleTypes hostBaseRole = RoleTypes.Crewmate) { if (player == null) return; @@ -749,6 +757,7 @@ internal class SelectRolesPatch Logger.Info($"Register Modded Role:{player.Data?.PlayerName} => {role}", "AssignRoles"); } + public static void MakeDesyncSender(Dictionary senders, Dictionary<(byte, byte), RoleTypes> rolesMap) { foreach (PlayerControl seer in Main.AllPlayerControls) @@ -774,47 +783,47 @@ internal class SelectRolesPatch SetColorPatch.IsAntiGlitchDisabled = false; } -// private static void ForceAssignRole(/*CustomRoles role,*/ List AllPlayers, CustomRpcSender sender, RoleTypes BaseRole, RoleTypes hostBaseRole = RoleTypes.Crewmate, bool skip = false, int Count = -1) -// { -// var count = 1; -// -// if (Count != -1) -// count = Count; -// for (var i = 0; i < count; i++) -// { -// if (AllPlayers.Count == 0) break; -// var rand = IRandom.Instance; -// var player = AllPlayers[rand.Next(0, AllPlayers.Count)]; -// AllPlayers.Remove(player); -// if (!skip) -// { -// if (!player.IsModClient()) -// { -// int playerCID = player.GetClientId(); -// sender.RpcSetRole(player, BaseRole, playerCID); -// //Desyncする人視点で他プレイヤーを科学者にするループ -// foreach (var pc in PlayerControl.AllPlayerControls) -// { -// if (pc == player) continue; -// sender.RpcSetRole(pc, RoleTypes.Scientist, playerCID); -// } -// //他視点でDesyncする人の役職を科学者にするループ -// foreach (var pc in PlayerControl.AllPlayerControls) -// { -// if (pc == player) continue; -// if (pc.PlayerId == 0) player.SetRole(RoleTypes.Scientist); //ホスト視点用 -// else sender.RpcSetRole(player, RoleTypes.Scientist, pc.GetClientId()); -// } -// } -// else -// { -// //ホストは別の役職にする -// player.SetRole(hostBaseRole); //ホスト視点用 -// sender.RpcSetRole(player, hostBaseRole); -// } -// } -// } -// } + // private static void ForceAssignRole(/*CustomRoles role,*/ List AllPlayers, CustomRpcSender sender, RoleTypes BaseRole, RoleTypes hostBaseRole = RoleTypes.Crewmate, bool skip = false, int Count = -1) + // { + // var count = 1; + // + // if (Count != -1) + // count = Count; + // for (var i = 0; i < count; i++) + // { + // if (AllPlayers.Count == 0) break; + // var rand = IRandom.Instance; + // var player = AllPlayers[rand.Next(0, AllPlayers.Count)]; + // AllPlayers.Remove(player); + // if (!skip) + // { + // if (!player.IsModClient()) + // { + // int playerCID = player.GetClientId(); + // sender.RpcSetRole(player, BaseRole, playerCID); + // //Desyncする人視点で他プレイヤーを科学者にするループ + // foreach (var pc in PlayerControl.AllPlayerControls) + // { + // if (pc == player) continue; + // sender.RpcSetRole(pc, RoleTypes.Scientist, playerCID); + // } + // //他視点でDesyncする人の役職を科学者にするループ + // foreach (var pc in PlayerControl.AllPlayerControls) + // { + // if (pc == player) continue; + // if (pc.PlayerId == 0) player.SetRole(RoleTypes.Scientist); //ホスト視点用 + // else sender.RpcSetRole(player, RoleTypes.Scientist, pc.GetClientId()); + // } + // } + // else + // { + // //ホストは別の役職にする + // player.SetRole(hostBaseRole); //ホスト視点用 + // sender.RpcSetRole(player, hostBaseRole); + // } + // } + // } + // } private static void AssignLoversRolesFromList() { @@ -825,6 +834,7 @@ internal class SelectRolesPatch AssignLoversRoles(); } } + private static void AssignLoversRoles(int RawCount = -1) { var allPlayers = Main.AllPlayerControls.Where(pc => !pc.Is(CustomRoles.GM) && (!pc.HasSubRole() || pc.GetCustomSubRoles().Count < Options.NoLimitAddonsNumMax.GetInt()) && !pc.Is(CustomRoles.Dictator) && !pc.Is(CustomRoles.God) && !pc.Is(CustomRoles.FFF) && !pc.Is(CustomRoles.Bomber) && !pc.Is(CustomRoles.Nuker) && !pc.Is(CustomRoles.Provocateur) && (!pc.GetCustomRole().IsCrewmate() || Options.CrewCanBeInLove.GetBool()) && (!pc.GetCustomRole().IsNeutral() || Options.NeutralCanBeInLove.GetBool()) && (!pc.GetCustomRole().IsImpostor() || Options.ImpCanBeInLove.GetBool())).ToList(); @@ -841,8 +851,10 @@ internal class SelectRolesPatch Main.PlayerStates[player.PlayerId].SetSubRole(role); Logger.Info("Add-on assigned: " + player?.Data?.PlayerName + " = " + player.GetCustomRole() + " + " + role, "AssignLovers"); } + RPC.SyncLoversPlayers(); } + private static void AssignSubRoles(CustomRoles role, int RawCount = -1) { var allPlayers = Main.AllAlivePlayerControls.Where(x => CustomRolesHelper.CheckAddonConflict(role, x)).ToArray(); @@ -862,9 +874,12 @@ internal class SelectRolesPatch { private static bool doReplace; public static Dictionary senders; + public static List<(PlayerControl, RoleTypes)> StoragedData = []; + // A list of Senders that does not require additional writing because SetRoleRpc has already been written in another process such as role Desync. public static List OverriddenSenderList; + public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)] RoleTypes roleType) { if (doReplace && senders != null) @@ -875,6 +890,7 @@ internal class SelectRolesPatch return true; } + public static void Release() { foreach (var sender in senders) @@ -890,10 +906,13 @@ internal class SelectRolesPatch .Write((ushort)ROLETYPE) .EndRpc(); } + sender.Value.EndMessage(); } + doReplace = false; } + public static void StartReplace(Dictionary senders) { RpcSetRoleReplacer.senders = senders; diff --git a/Roles/AddOns/Crewmate/Stressed.cs b/Roles/AddOns/Crewmate/Stressed.cs index 4902dcb47..6d9f9fc05 100644 --- a/Roles/AddOns/Crewmate/Stressed.cs +++ b/Roles/AddOns/Crewmate/Stressed.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; -using Hazel; using static TOHE.Options; using static TOHE.Translator; @@ -95,6 +95,7 @@ namespace TOHE.Roles.AddOns.Crewmate Main.PlayerStates[pc.PlayerId].RemoveSubRole(CustomRoles.Stressed); continue; } + Timers.Add(pc.PlayerId, StartingTime); LastUpdates.Add(pc.PlayerId, now + 1); } @@ -207,4 +208,4 @@ namespace TOHE.Roles.AddOns.Crewmate } } } -} +} \ No newline at end of file diff --git a/Roles/AddOns/Impostor/Damocles.cs b/Roles/AddOns/Impostor/Damocles.cs index 32a55b066..4a00088aa 100644 --- a/Roles/AddOns/Impostor/Damocles.cs +++ b/Roles/AddOns/Impostor/Damocles.cs @@ -1,7 +1,7 @@ -using System; +using Hazel; +using System; using System.Collections.Generic; using System.Linq; -using Hazel; using static TOHE.Options; using static TOHE.Translator; @@ -62,6 +62,7 @@ namespace TOHE.Roles.AddOns.Impostor Main.PlayerStates[id].RemoveSubRole(CustomRoles.Damocles); return; } + lastUpdate[id] = now; if (!Timer.ContainsKey(id)) Timer[id] = StartingTime + 8; @@ -85,7 +86,9 @@ namespace TOHE.Roles.AddOns.Impostor writer.Write(Timer[playerId]); writer.Write(lastUpdate[playerId].ToString()); writer.Write(PreviouslyEnteredVents[playerId].Count); - if (PreviouslyEnteredVents[playerId].Count > 0) foreach (var vent in PreviouslyEnteredVents[playerId].ToArray()) writer.Write(vent); + if (PreviouslyEnteredVents[playerId].Count > 0) + foreach (var vent in PreviouslyEnteredVents[playerId].ToArray()) + writer.Write(vent); AmongUsClient.Instance.FinishRpcImmediately(writer); } @@ -95,7 +98,9 @@ namespace TOHE.Roles.AddOns.Impostor Timer[playerId] = reader.ReadInt32(); lastUpdate[playerId] = long.Parse(reader.ReadString()); var elements = reader.ReadInt32(); - if (elements > 0) for (int i = 0; i < elements; i++) PreviouslyEnteredVents[playerId].Add(reader.ReadInt32()); + if (elements > 0) + for (int i = 0; i < elements; i++) + PreviouslyEnteredVents[playerId].Add(reader.ReadInt32()); } public static void OnMurder(byte id) diff --git a/Roles/Crewmate/Aid.cs b/Roles/Crewmate/Aid.cs index a2dd51f67..362e0abe6 100644 --- a/Roles/Crewmate/Aid.cs +++ b/Roles/Crewmate/Aid.cs @@ -47,6 +47,7 @@ namespace TOHE.Roles.Crewmate public override void SetKillCooldown(byte playerId) => Main.AllPlayerKillCooldown[playerId] = AidCD.GetInt(); public override bool IsEnable => playerIdList.Count > 0; + public override bool CanUseKillButton(PlayerControl pc) => pc.GetAbilityUseLimit() >= 1; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { diff --git a/Roles/Crewmate/Alchemist.cs b/Roles/Crewmate/Alchemist.cs index 357ac643e..3cde39b1c 100644 --- a/Roles/Crewmate/Alchemist.cs +++ b/Roles/Crewmate/Alchemist.cs @@ -236,6 +236,7 @@ namespace TOHE.Roles.Crewmate public override void OnCoEnterVent(PlayerPhysics instance, int ventId) { + if (PotionID != 6) return; PotionID = 10; var pc = instance.myPlayer; NameNotifyManager.Notice.Remove(pc.PlayerId); @@ -408,5 +409,10 @@ namespace TOHE.Roles.Crewmate break; } } + + public override bool OnCheckMurderAsTarget(PlayerControl killer, PlayerControl target) + { + return !IsProtected; + } } } \ No newline at end of file diff --git a/Roles/Crewmate/Analyzer.cs b/Roles/Crewmate/Analyzer.cs index 95e723c42..0ae905766 100644 --- a/Roles/Crewmate/Analyzer.cs +++ b/Roles/Crewmate/Analyzer.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using AmongUs.GameOptions; +using System.Collections.Generic; using System.Linq; -using AmongUs.GameOptions; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; diff --git a/Roles/Crewmate/Bloodhound.cs b/Roles/Crewmate/Bloodhound.cs index af030e3bb..11cbb4c96 100644 --- a/Roles/Crewmate/Bloodhound.cs +++ b/Roles/Crewmate/Bloodhound.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; -using Hazel; using UnityEngine; namespace TOHE.Roles.Crewmate @@ -83,7 +83,7 @@ namespace TOHE.Roles.Crewmate public override void OnReportDeadBody() { - foreach (byte apc in playerIdList.ToArray()) + foreach (byte apc in playerIdList) { LocateArrow.RemoveAllTarget(apc); SendRPC(apc, false); @@ -96,7 +96,7 @@ namespace TOHE.Roles.Crewmate { if (!ArrowsPointingToDeadBody.GetBool()) return; - foreach (byte pc in playerIdList.ToArray()) + foreach (byte pc in playerIdList) { var player = Utils.GetPlayerById(pc); if (player == null || !player.IsAlive()) diff --git a/Roles/Crewmate/CandleLighter.cs b/Roles/Crewmate/CandleLighter.cs index 60fb34888..3121fac2e 100644 --- a/Roles/Crewmate/CandleLighter.cs +++ b/Roles/Crewmate/CandleLighter.cs @@ -1,6 +1,6 @@ -using System; +using AmongUs.GameOptions; +using System; using System.Collections.Generic; -using AmongUs.GameOptions; using UnityEngine; namespace TOHE.Roles.Crewmate diff --git a/Roles/Crewmate/Cleanser.cs b/Roles/Crewmate/Cleanser.cs index 32c7920a2..f6f5c31da 100644 --- a/Roles/Crewmate/Cleanser.cs +++ b/Roles/Crewmate/Cleanser.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; diff --git a/Roles/Crewmate/CopyCat.cs b/Roles/Crewmate/CopyCat.cs index 28e52c87b..607291887 100644 --- a/Roles/Crewmate/CopyCat.cs +++ b/Roles/Crewmate/CopyCat.cs @@ -50,7 +50,7 @@ public class CopyCat : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = Utils.GetPlayerById(id).IsAlive() ? CurrentKillCooldown[id] : 0f; - public override void AfterMeetingTasks() + public static void ResetRole() { foreach (var player in playerIdList) { @@ -62,15 +62,6 @@ public class CopyCat : RoleBase case CustomRoles.Cleanser: Cleanser.DidVote.Remove(pc.PlayerId); break; - case CustomRoles.Jailor: - Jailor.JailorExeLimit.Remove(pc.PlayerId); - Jailor.JailorTarget.Remove(pc.PlayerId); - Jailor.JailorHasExe.Remove(pc.PlayerId); - Jailor.JailorDidVote.Remove(pc.PlayerId); - break; - case CustomRoles.Medic: - Medic.ProtectLimit.Remove(player); - break; case CustomRoles.Merchant: Merchant.addonsSold.Remove(player); Merchant.bribedKiller.Remove(player); @@ -82,19 +73,13 @@ public class CopyCat : RoleBase Snitch.IsExposed.Remove(player); Snitch.IsComplete.Remove(player); break; - case CustomRoles.Sheriff: - Sheriff.CurrentKillCooldown.Remove(player); - break; - case CustomRoles.Crusader: - Crusader.CurrentKillCooldown.Remove(player); - break; case CustomRoles.Mayor: Main.MayorUsedButtonCount.Remove(player); break; } pc.RpcSetCustomRole(CustomRoles.CopyCat); - SetKillCooldown(player); + (Main.PlayerStates[player].Role as CopyCat)?.SetKillCooldown(player); } } @@ -153,8 +138,6 @@ public class CopyCat : RoleBase //////////// /*add the settings for new role*/ //////////// /* anything that is assigned in onGameStartedPatch.cs comes here */ - Utils.AddRoles(pc.PlayerId, role); - pc.RpcSetCustomRole(role); pc.SetAbilityUseLimit(tpc.GetAbilityUseLimit()); diff --git a/Roles/Crewmate/Crusader.cs b/Roles/Crewmate/Crusader.cs index 2628d6d1a..619743381 100644 --- a/Roles/Crewmate/Crusader.cs +++ b/Roles/Crewmate/Crusader.cs @@ -47,6 +47,7 @@ public class Crusader : RoleBase && (pc.GetAbilityUseLimit() >= 1); public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(Utils.GetPlayerById(id)) ? CurrentKillCooldown : 15f; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { diff --git a/Roles/Crewmate/Deputy.cs b/Roles/Crewmate/Deputy.cs index 60e2b02e0..77a421917 100644 --- a/Roles/Crewmate/Deputy.cs +++ b/Roles/Crewmate/Deputy.cs @@ -47,6 +47,7 @@ public class Deputy : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = HandcuffCooldown.GetFloat(); public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead && player.GetAbilityUseLimit() >= 1; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { diff --git a/Roles/Crewmate/Doctor.cs b/Roles/Crewmate/Doctor.cs index da1765b14..16bdcef2f 100644 --- a/Roles/Crewmate/Doctor.cs +++ b/Roles/Crewmate/Doctor.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AmongUs.GameOptions; +using AmongUs.GameOptions; namespace TOHE.Roles.Crewmate { @@ -28,4 +23,4 @@ namespace TOHE.Roles.Crewmate AURoleOptions.ScientistBatteryCharge = Options.DoctorTaskCompletedBatteryCharge.GetFloat(); } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/DonutDelivery.cs b/Roles/Crewmate/DonutDelivery.cs index ceeeec741..421748892 100644 --- a/Roles/Crewmate/DonutDelivery.cs +++ b/Roles/Crewmate/DonutDelivery.cs @@ -48,6 +48,8 @@ namespace TOHE.Roles.Crewmate Main.AllPlayerKillCooldown[playerId] = playerId.GetAbilityUseLimit() > 0 ? CD.GetFloat() : 300f; } + public override bool CanUseKillButton(PlayerControl pc) => pc.GetAbilityUseLimit() >= 1; + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (!IsEnable || killer == null || target == null || killer.GetAbilityUseLimit() <= 0) return true; diff --git a/Roles/Crewmate/Drainer.cs b/Roles/Crewmate/Drainer.cs index 476cd425e..a98a7a950 100644 --- a/Roles/Crewmate/Drainer.cs +++ b/Roles/Crewmate/Drainer.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using HarmonyLib; +using System.Collections.Generic; +using System.Linq; using static TOHE.Options; namespace TOHE.Roles.Crewmate diff --git a/Roles/Crewmate/Druid.cs b/Roles/Crewmate/Druid.cs index b22f9b4e6..26abf4ac1 100644 --- a/Roles/Crewmate/Druid.cs +++ b/Roles/Crewmate/Druid.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; using System.Text; -using Hazel; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -72,6 +72,7 @@ namespace TOHE.Roles.Crewmate if (add) writer.Write(roomName); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPCAddTrigger(MessageReader reader) { bool add = reader.ReadBoolean(); @@ -202,8 +203,8 @@ namespace TOHE.Roles.Crewmate if (!Triggers.TryGetValue(id, out var triggers)) return sb.ToString(); string GetCD_HUDText() => !UsePets.GetBool() || !Main.AbilityCD.TryGetValue(id, out var CD) - ? string.Empty - : string.Format(GetString("CDPT"), CD.TOTALCD - (TimeStamp - CD.START_TIMESTAMP) + 1); + ? string.Empty + : string.Format(GetString("CDPT"), CD.TOTALCD - (TimeStamp - CD.START_TIMESTAMP) + 1); sb.AppendLine($"<#00ffa5>{triggers.Count} trigger{(triggers.Count == 1 ? string.Empty : 's')} active"); sb.Append(string.Join('\n', triggers.Select(trigger => $"Trigger {GetFormattedRoomName(trigger.Value)} {GetFormattedVectorText(trigger.Key)}"))); @@ -211,4 +212,4 @@ namespace TOHE.Roles.Crewmate return sb.ToString(); } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Escort.cs b/Roles/Crewmate/Escort.cs index 54877f9a1..ed222252c 100644 --- a/Roles/Crewmate/Escort.cs +++ b/Roles/Crewmate/Escort.cs @@ -48,6 +48,8 @@ namespace TOHE.Roles.Crewmate Main.AllPlayerKillCooldown[playerId] = playerId.GetAbilityUseLimit() > 0 ? CD.GetFloat() : 300f; } + public override bool CanUseKillButton(PlayerControl pc) => pc.GetAbilityUseLimit() >= 1; + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (!IsEnable || killer == null || target == null || killer.GetAbilityUseLimit() <= 0) return false; diff --git a/Roles/Crewmate/Farseer.cs b/Roles/Crewmate/Farseer.cs index 86b1a78c0..1f90063f0 100644 --- a/Roles/Crewmate/Farseer.cs +++ b/Roles/Crewmate/Farseer.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using AmongUs.GameOptions; +using System.Collections.Generic; using System.Linq; -using AmongUs.GameOptions; using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; using UnityEngine; @@ -51,6 +51,13 @@ namespace TOHE.Roles.Crewmate { On = true; + foreach (PlayerControl ar in Main.AllPlayerControls) + { + Main.isRevealed.Add((playerId, ar.PlayerId), false); + } + + RandomRole.Add(playerId, GetRandomCrewRoleString()); + if (!AmongUsClient.Instance.AmHost || (UsePets.GetBool() && UsePet.GetBool())) return; if (!Main.ResetCamPlayerList.Contains(playerId)) Main.ResetCamPlayerList.Add(playerId); @@ -153,4 +160,4 @@ namespace TOHE.Roles.Crewmate return $" " + ColorString(TextColor, $"({Completed}/{taskState.AllTasksCount})") + "\r\n"; } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Gaulois.cs b/Roles/Crewmate/Gaulois.cs index 34515ee34..e1b6b549c 100644 --- a/Roles/Crewmate/Gaulois.cs +++ b/Roles/Crewmate/Gaulois.cs @@ -54,6 +54,8 @@ namespace TOHE.Roles.Crewmate Main.AllPlayerKillCooldown[playerId] = playerId.GetAbilityUseLimit() > 0 ? CD.GetFloat() : 300f; } + public override bool CanUseKillButton(PlayerControl pc) => pc.GetAbilityUseLimit() >= 1; + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (!IsEnable || killer == null || target == null || killer.GetAbilityUseLimit() <= 0) return false; diff --git a/Roles/Crewmate/Grenadier.cs b/Roles/Crewmate/Grenadier.cs index f10bb3ac6..eeddd84bb 100644 --- a/Roles/Crewmate/Grenadier.cs +++ b/Roles/Crewmate/Grenadier.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; -using System.Text; +using AmongUs.GameOptions; using HarmonyLib; +using System.Collections.Generic; +using System.Linq; +using System.Text; using TOHE.Modules; namespace TOHE.Roles.Crewmate @@ -114,4 +114,4 @@ namespace TOHE.Roles.Crewmate } } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Jailer.cs b/Roles/Crewmate/Jailer.cs index 4e406f365..807543bee 100644 --- a/Roles/Crewmate/Jailer.cs +++ b/Roles/Crewmate/Jailer.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using Hazel; +using System.Collections.Generic; using static TOHE.Options; using static TOHE.Translator; @@ -110,5 +110,4 @@ public class Jailor : RoleBase _ = new LateTask(() => { Utils.SendMessage(GetString("JailedNotifyMsg"), JailorTarget, title: Utils.ColorString(Utils.GetRoleColor(CustomRoles.Jailor), GetString("JailorTitle"))); }, 0.3f, "JailorNotifyJailed"); } } - } \ No newline at end of file diff --git a/Roles/Crewmate/Judge.cs b/Roles/Crewmate/Judge.cs index 387d98ae3..681d20930 100644 --- a/Roles/Crewmate/Judge.cs +++ b/Roles/Crewmate/Judge.cs @@ -1,9 +1,9 @@ -using System; +using HarmonyLib; +using Hazel; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -using HarmonyLib; -using Hazel; using UnityEngine; using static TOHE.Translator; using Object = UnityEngine.Object; diff --git a/Roles/Crewmate/Lookout.cs b/Roles/Crewmate/Lookout.cs index 95d7c694a..3b5973bde 100644 --- a/Roles/Crewmate/Lookout.cs +++ b/Roles/Crewmate/Lookout.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Text; namespace TOHE.Roles.Crewmate { @@ -43,4 +39,4 @@ namespace TOHE.Roles.Crewmate pc.Notify(sb.ToString()); } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Luckey.cs b/Roles/Crewmate/Luckey.cs index ba6c3fd1f..f0904e26a 100644 --- a/Roles/Crewmate/Luckey.cs +++ b/Roles/Crewmate/Luckey.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TOHE.Roles.Crewmate +namespace TOHE.Roles.Crewmate { internal class Luckey : RoleBase { @@ -33,4 +27,4 @@ namespace TOHE.Roles.Crewmate return true; } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Mayor.cs b/Roles/Crewmate/Mayor.cs index 869aff5d8..6e0fb7883 100644 --- a/Roles/Crewmate/Mayor.cs +++ b/Roles/Crewmate/Mayor.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AmongUs.GameOptions; +using AmongUs.GameOptions; namespace TOHE.Roles.Crewmate { @@ -60,4 +55,4 @@ namespace TOHE.Roles.Crewmate } } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Medic.cs b/Roles/Crewmate/Medic.cs index 591ac39fb..0d64d2d43 100644 --- a/Roles/Crewmate/Medic.cs +++ b/Roles/Crewmate/Medic.cs @@ -108,17 +108,18 @@ public class Medic : RoleBase ProtectList.Add(reader.ReadByte()); } - public static bool CanUseKillButton(byte playerId) - => !Main.PlayerStates[playerId].IsDead - && playerId.GetAbilityUseLimit() >= 1; + public override bool CanUseKillButton(PlayerControl pc) + => !Main.PlayerStates[pc.PlayerId].IsDead + && pc.GetAbilityUseLimit() >= 1; - public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(id) ? CD.GetFloat() : 300f; + public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(Utils.GetPlayerById(id)) ? CD.GetFloat() : 300f; public static bool InProtect(byte id) => ProtectList.Contains(id) && Main.PlayerStates.TryGetValue(id, out var ps) && !ps.IsDead; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (killer == null || target == null) return false; - if (!CanUseKillButton(killer.PlayerId)) return false; + if (!CanUseKillButton(killer)) return false; if (ProtectList.Contains(target.PlayerId)) return false; killer.RpcRemoveAbilityUse(); diff --git a/Roles/Crewmate/Monarch.cs b/Roles/Crewmate/Monarch.cs index 7855277f7..e5e981379 100644 --- a/Roles/Crewmate/Monarch.cs +++ b/Roles/Crewmate/Monarch.cs @@ -41,6 +41,7 @@ public class Monarch : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KnightCooldown.GetFloat(); public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead && player.GetAbilityUseLimit() >= 1; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { diff --git a/Roles/Crewmate/Mortician.cs b/Roles/Crewmate/Mortician.cs index 9e6fcf512..861439a2e 100644 --- a/Roles/Crewmate/Mortician.cs +++ b/Roles/Crewmate/Mortician.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; @@ -47,6 +47,7 @@ public class Mortician : RoleBase writer.Write(loc.y); writer.Write(loc.z); } + AmongUsClient.Instance.FinishRpcImmediately(writer); } @@ -59,6 +60,7 @@ public class Mortician : RoleBase else LocateArrow.RemoveAllTarget(playerId); } + public static void OnPlayerDead(PlayerControl target) { var pos = target.Pos(); @@ -84,6 +86,7 @@ public class Mortician : RoleBase SendRPC(pc, true, target.transform.position); } } + public static void OnReportDeadBody(PlayerControl pc, GameData.PlayerInfo target) { foreach (byte apc in playerIdList) @@ -96,6 +99,7 @@ public class Mortician : RoleBase lastPlayerName.TryGetValue(target.PlayerId, out var name); msgToSend.Add(pc.PlayerId, name == "" ? string.Format(Translator.GetString("MorticianGetNoInfo"), target.PlayerName) : string.Format(Translator.GetString("MorticianGetInfo"), target.PlayerName, name)); } + public static string GetTargetArrow(PlayerControl seer, PlayerControl target = null) { if (ShowArrows.GetBool()) diff --git a/Roles/Crewmate/NiceHacker.cs b/Roles/Crewmate/NiceHacker.cs index b0599dd39..d506f164f 100644 --- a/Roles/Crewmate/NiceHacker.cs +++ b/Roles/Crewmate/NiceHacker.cs @@ -1,7 +1,7 @@ -using System; +using Hazel; +using System; using System.Collections.Generic; using System.Text; -using Hazel; using UnityEngine; namespace TOHE.Roles.Crewmate diff --git a/Roles/Crewmate/Paranoia.cs b/Roles/Crewmate/Paranoia.cs index 291632b4f..d74d8eea4 100644 --- a/Roles/Crewmate/Paranoia.cs +++ b/Roles/Crewmate/Paranoia.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AmongUs.GameOptions; +using AmongUs.GameOptions; namespace TOHE.Roles.Crewmate { @@ -66,4 +61,4 @@ namespace TOHE.Roles.Crewmate } } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/ParityCop.cs b/Roles/Crewmate/ParityCop.cs index 132d1a33a..2fb0f9788 100644 --- a/Roles/Crewmate/ParityCop.cs +++ b/Roles/Crewmate/ParityCop.cs @@ -1,7 +1,7 @@ +using HarmonyLib; using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; diff --git a/Roles/Crewmate/Psychic.cs b/Roles/Crewmate/Psychic.cs index da739824e..7cd32e673 100644 --- a/Roles/Crewmate/Psychic.cs +++ b/Roles/Crewmate/Psychic.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; using AmongUs.GameOptions; using HarmonyLib; using Hazel; +using System; +using System.Collections.Generic; +using System.Linq; using static TOHE.Options; namespace TOHE.Roles.Crewmate; @@ -61,6 +61,7 @@ public class Psychic : RoleBase AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte playerId = reader.ReadByte(); @@ -90,10 +91,10 @@ public class Psychic : RoleBase if (!IsEnable || !AmongUsClient.Instance.AmHost) return; List BadListPc = Main.AllAlivePlayerControls.Where(x => - (x.Is(CustomRoleTypes.Impostor) && !x.Is(CustomRoles.Trickster)) || x.Is(CustomRoles.Madmate) || x.Is(CustomRoles.Rascal) || x.Is(CustomRoles.Recruit) || x.Is(CustomRoles.Charmed) || x.Is(CustomRoles.Contagious) || - (x.GetCustomRole().IsCK() && CkshowEvil.GetBool()) || - (x.GetCustomRole().IsNE() && NEshowEvil.GetBool()) || - (x.GetCustomRole().IsNB() && NBshowEvil.GetBool()) + (x.Is(CustomRoleTypes.Impostor) && !x.Is(CustomRoles.Trickster)) || x.Is(CustomRoles.Madmate) || x.Is(CustomRoles.Rascal) || x.Is(CustomRoles.Recruit) || x.Is(CustomRoles.Charmed) || x.Is(CustomRoles.Contagious) || + (x.GetCustomRole().IsCK() && CkshowEvil.GetBool()) || + (x.GetCustomRole().IsNE() && NEshowEvil.GetBool()) || + (x.GetCustomRole().IsNB() && NBshowEvil.GetBool()) ).ToList(); List BadList = []; @@ -103,7 +104,8 @@ public class Psychic : RoleBase int ENum = 1; for (int i = 1; i < CanSeeNum.GetInt(); i++) - if (IRandom.Instance.Next(0, 100) < 18) ENum++; + if (IRandom.Instance.Next(0, 100) < 18) + ENum++; int BNum = CanSeeNum.GetInt() - ENum; ENum = Math.Min(ENum, BadList.Count); BNum = Math.Min(BNum, AllList.Count); diff --git a/Roles/Crewmate/Rabbit.cs b/Roles/Crewmate/Rabbit.cs index 416e27b04..169d17539 100644 --- a/Roles/Crewmate/Rabbit.cs +++ b/Roles/Crewmate/Rabbit.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; -using Hazel; namespace TOHE.Roles.Crewmate { @@ -51,13 +51,15 @@ namespace TOHE.Roles.Crewmate } public string Suffix => !GameStates.IsInTask || !Arrow.HasArrow - ? string.Empty - : Utils.ColorString(Utils.GetRoleColor(CustomRoles.Rabbit), TargetArrow.GetArrows(Player, Arrow.Target)); + ? string.Empty + : Utils.ColorString(Utils.GetRoleColor(CustomRoles.Rabbit), TargetArrow.GetArrows(Player, Arrow.Target)); } + private static int Id => 643330; private static readonly Dictionary RabbitStates = []; private static OptionItem OptionTaskTrigger; private static int TaskTrigger; + public static void SetupCustomOption() { Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Rabbit); @@ -88,6 +90,7 @@ namespace TOHE.Roles.Crewmate if (pc == null || !RabbitStates.TryGetValue(pc.PlayerId, out RabbitState state)) return; state.OnTaskComplete(); } + public static string GetSuffix(PlayerControl pc, bool HUD = false) { if (pc == null || !RabbitStates.TryGetValue(pc.PlayerId, out RabbitState state)) return string.Empty; @@ -95,4 +98,4 @@ namespace TOHE.Roles.Crewmate return HUD ? $"{suffix}" : suffix; } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Randomizer.cs b/Roles/Crewmate/Randomizer.cs index 2410ca731..364382389 100644 --- a/Roles/Crewmate/Randomizer.cs +++ b/Roles/Crewmate/Randomizer.cs @@ -645,6 +645,7 @@ namespace TOHE.Roles.Crewmate { pc.Suicide(PlayerState.DeathReason.RNG, randomizer); } + Bombs.Remove(bomb.Key); } } @@ -709,6 +710,7 @@ namespace TOHE.Roles.Crewmate LastTP[pc.PlayerId] = now; return; } + if (Vector2.Distance(pos, rift.Value) < 2f) { pc.TP(rift.Key); @@ -742,6 +744,7 @@ namespace TOHE.Roles.Crewmate { RevertVisionChangesForPlayer(pc, true); } + if (item.Key.IsSpeedChangingEffect()) { RevertSpeedChangesForPlayer(pc, true); @@ -759,4 +762,4 @@ namespace TOHE.Roles.Crewmate } } } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/SabotageMaster.cs b/Roles/Crewmate/SabotageMaster.cs index e59712565..fbd75e1de 100644 --- a/Roles/Crewmate/SabotageMaster.cs +++ b/Roles/Crewmate/SabotageMaster.cs @@ -63,7 +63,7 @@ public class SabotageMaster : RoleBase public override bool IsEnable => playerIdList.Count > 0; - void SendRPC() + public void SendRPC() { if (!IsEnable || !Utils.DoRPC) return; MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetSabotageMasterLimit, SendOption.Reliable); diff --git a/Roles/Crewmate/Sentinel.cs b/Roles/Crewmate/Sentinel.cs index 291b6606b..ced33ff71 100644 --- a/Roles/Crewmate/Sentinel.cs +++ b/Roles/Crewmate/Sentinel.cs @@ -126,7 +126,8 @@ namespace TOHE.Roles.Crewmate public static PatrollingState GetPatrollingState(byte playerId) => PatrolStates.FirstOrDefault(x => x.SentinelId == playerId) ?? new(playerId, PatrolDuration.GetInt(), PatrolRadius.GetInt()); public static bool IsPatrolling(byte playerId) => GetPatrollingState(playerId).IsPatrolling; - public static void StartPatrolling(PlayerControl pc) => GetPatrollingState(pc.PlayerId)?.StartPatrolling(); + public override void OnEnterVent(PlayerControl pc, Vent vent) => GetPatrollingState(pc.PlayerId)?.StartPatrolling(); + public static bool OnAnyoneCheckMurder(PlayerControl killer) { if (killer == null || !PatrolStates.Any(x => x.IsPatrolling)) return true; diff --git a/Roles/Crewmate/Sheriff.cs b/Roles/Crewmate/Sheriff.cs index 463e99ccc..454b67a1d 100644 --- a/Roles/Crewmate/Sheriff.cs +++ b/Roles/Crewmate/Sheriff.cs @@ -103,6 +103,8 @@ public class Sheriff : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CanUseKillButton(Utils.GetPlayerById(id)) ? KillCooldown.GetFloat() : 15f; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; + public override bool CanUseKillButton(PlayerControl pc) => !Main.PlayerStates[pc.PlayerId].IsDead && (CanKillAllAlive.GetBool() || GameStates.AlreadyDied) diff --git a/Roles/Crewmate/Spy.cs b/Roles/Crewmate/Spy.cs index fca916bde..3d6d87207 100644 --- a/Roles/Crewmate/Spy.cs +++ b/Roles/Crewmate/Spy.cs @@ -85,14 +85,16 @@ namespace TOHE.Roles.Crewmate } } - public static void OnKillAttempt(PlayerControl killer, PlayerControl target) // Special handling for Spy ---- remains as a static method + public static bool OnKillAttempt(PlayerControl killer, PlayerControl target) // Special handling for Spy ---- remains as a static method { - if (killer == null || target == null || !target.Is(CustomRoles.Spy) || killer.PlayerId == target.PlayerId || target.GetAbilityUseLimit() < 1) return; + if (killer == null || target == null || !target.Is(CustomRoles.Spy) || killer.PlayerId == target.PlayerId || target.GetAbilityUseLimit() < 1) return true; target.RpcRemoveAbilityUse(); SpyRedNameList.TryAdd(killer.PlayerId, TimeStamp); SendRPC(1, id: killer.PlayerId); NotifyRoles(SpecifySeer: target, SpecifyTarget: killer); + + return false; } public override void OnFixedUpdate(PlayerControl pc) diff --git a/Roles/Crewmate/SwordsMan.cs b/Roles/Crewmate/SwordsMan.cs index 864641f10..eefef1142 100644 --- a/Roles/Crewmate/SwordsMan.cs +++ b/Roles/Crewmate/SwordsMan.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using UnityEngine; namespace TOHE.Roles.Crewmate; @@ -27,6 +27,7 @@ public class SwordsMan : RoleBase } public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = IsKilled(id) ? 300f : Options.DefaultKillCooldown; + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public override string GetProgressText(byte id, bool comms) => Utils.ColorString(!IsKilled(id) ? Utils.GetRoleColor(CustomRoles.SwordsMan).ShadeColor(0.25f) : Color.gray, !IsKilled(id) ? "(1)" : "(0)"); public override bool CanUseKillButton(PlayerControl pc) @@ -53,6 +54,7 @@ public class SwordsMan : RoleBase writer.Write(playerId); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte SwordsManId = reader.ReadByte(); diff --git a/Roles/Crewmate/Tether.cs b/Roles/Crewmate/Tether.cs index 7f5aeff0c..1ea032fc9 100644 --- a/Roles/Crewmate/Tether.cs +++ b/Roles/Crewmate/Tether.cs @@ -1,6 +1,6 @@ +using Hazel; using System.Collections.Generic; using System.Text; -using Hazel; namespace TOHE.Roles.Crewmate { @@ -60,6 +60,7 @@ namespace TOHE.Roles.Crewmate writer.Write(Target); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPCSyncTarget(MessageReader reader) { byte id = reader.ReadByte(); @@ -94,12 +95,10 @@ namespace TOHE.Roles.Crewmate } else if (!isPet) { - _ = new LateTask(() => - { - pc.MyPhysics?.RpcBootFromVent(ventId); - }, 0.5f, "Tether No Target Boot From Vent"); + _ = new LateTask(() => { pc.MyPhysics?.RpcBootFromVent(ventId); }, 0.5f, "Tether No Target Boot From Vent"); } } + public static bool OnVote(PlayerControl pc, PlayerControl target) { if (pc == null || target == null || Main.PlayerStates[pc.PlayerId].Role is not Tether th || pc.PlayerId == target.PlayerId || Main.DontCancelVoteList.Contains(pc.PlayerId)) return false; @@ -112,6 +111,7 @@ namespace TOHE.Roles.Crewmate Main.DontCancelVoteList.Add(pc.PlayerId); return true; } + return false; } diff --git a/Roles/Crewmate/Tornado.cs b/Roles/Crewmate/Tornado.cs index 4401a88ec..ae9581931 100644 --- a/Roles/Crewmate/Tornado.cs +++ b/Roles/Crewmate/Tornado.cs @@ -1,7 +1,7 @@ -using System; +using Hazel; +using System; using System.Collections.Generic; using System.Linq; -using Hazel; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -89,6 +89,7 @@ namespace TOHE.Roles.Crewmate if (add) writer.Write(timestamp.ToString()); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPCAddTornado(MessageReader reader) { bool add = reader.ReadBoolean(); @@ -146,6 +147,7 @@ namespace TOHE.Roles.Crewmate { Map.RandomTeleport(pc); } + pc.Notify(NotifyString); } @@ -163,6 +165,7 @@ namespace TOHE.Roles.Crewmate LastNotify = now; } } + public static string GetSuffixText(bool isHUD = false) => string.Join(isHUD ? "\n" : ", ", Tornados.Select(x => $"Tornado {GetFormattedRoomName(x.Key.ROOM_NAME)} {GetFormattedVectorText(x.Key.LOCATION)} ({(int)(TornadoDuration.GetInt() - (TimeStamp - x.Value) + 1)}s)")); } -} +} \ No newline at end of file diff --git a/Roles/Crewmate/Tracefinder.cs b/Roles/Crewmate/Tracefinder.cs index 4b1f5dbd8..322103ffc 100644 --- a/Roles/Crewmate/Tracefinder.cs +++ b/Roles/Crewmate/Tracefinder.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; using AmongUs.GameOptions; using Hazel; +using System; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; @@ -57,6 +57,7 @@ public class Tracefinder : RoleBase writer.Write(loc.y); writer.Write(loc.z); } + AmongUsClient.Instance.FinishRpcImmediately(writer); } @@ -65,6 +66,7 @@ public class Tracefinder : RoleBase AURoleOptions.ScientistCooldown = VitalsCooldown.GetFloat(); AURoleOptions.ScientistBatteryCharge = VitalsDuration.GetFloat(); } + public static void ReceiveRPC(MessageReader reader) { byte playerId = reader.ReadByte(); @@ -83,6 +85,7 @@ public class Tracefinder : RoleBase SendRPC(apc, false); } } + public static void OnPlayerDead(PlayerControl target) { var pos = target.Pos(); @@ -119,6 +122,7 @@ public class Tracefinder : RoleBase } }, delay, "Tracefinder arrow delay"); } + public static string GetTargetArrow(PlayerControl seer, PlayerControl target = null) { if (!seer.Is(CustomRoles.Tracefinder)) return string.Empty; diff --git a/Roles/Crewmate/Tracker.cs b/Roles/Crewmate/Tracker.cs index b48858cfd..5efda6877 100644 --- a/Roles/Crewmate/Tracker.cs +++ b/Roles/Crewmate/Tracker.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -66,6 +66,7 @@ namespace TOHE.Roles.Crewmate writer.Write(targetId); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte trackerId = reader.ReadByte(); @@ -76,6 +77,7 @@ namespace TOHE.Roles.Crewmate TrackerTarget[trackerId].Add(targetId); TargetArrow.Add(trackerId, targetId); } + public static string GetTargetMark(PlayerControl seer, PlayerControl target) => !(seer == null || target == null) && TrackerTarget.ContainsKey(seer.PlayerId) && TrackerTarget[seer.PlayerId].Contains(target.PlayerId) ? Utils.ColorString(seer.GetRoleColor(), "◀") : string.Empty; public static bool OnVote(PlayerControl player, PlayerControl target) @@ -112,13 +114,14 @@ namespace TOHE.Roles.Crewmate var arrow = TargetArrow.GetArrows(seer, trackTarget); arrows += Utils.ColorString(CanGetColoredArrow.GetBool() ? Palette.PlayerColors[targetData.Data.DefaultOutfit.ColorId] : Color.white, arrow); } + return arrows; } public static bool IsTrackTarget(PlayerControl seer, PlayerControl target) => seer.IsAlive() && playerIdList.Contains(seer.PlayerId) - && TrackerTarget[seer.PlayerId].Contains(target.PlayerId) - && target.IsAlive(); + && TrackerTarget[seer.PlayerId].Contains(target.PlayerId) + && target.IsAlive(); public static string GetArrowAndLastRoom(PlayerControl seer, PlayerControl target) { diff --git a/Roles/Crewmate/VanillaRole.cs b/Roles/Crewmate/VanillaRole.cs index 8a324c4b3..c6487e099 100644 --- a/Roles/Crewmate/VanillaRole.cs +++ b/Roles/Crewmate/VanillaRole.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TOHE +namespace TOHE { internal class VanillaRole : RoleBase { @@ -21,4 +15,4 @@ namespace TOHE On = false; } } -} +} \ No newline at end of file diff --git a/Roles/Impostor/Assassin.cs b/Roles/Impostor/Assassin.cs index 094edded5..46a6e25ce 100644 --- a/Roles/Impostor/Assassin.cs +++ b/Roles/Impostor/Assassin.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; using TOHE.Modules; using TOHE.Roles.Crewmate; using TOHE.Roles.Neutral; @@ -71,6 +71,7 @@ internal class Assassin : RoleBase writer.Write(MarkedPlayer); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte playerId = reader.ReadByte(); diff --git a/Roles/Impostor/BallLightning.cs b/Roles/Impostor/BallLightning.cs index 5525fbbb2..87a8a99d7 100644 --- a/Roles/Impostor/BallLightning.cs +++ b/Roles/Impostor/BallLightning.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using TOHE.Modules; using TOHE.Roles.Crewmate; using TOHE.Roles.Neutral; diff --git a/Roles/Impostor/Blackmailer.cs b/Roles/Impostor/Blackmailer.cs index a1f66bc23..82594417d 100644 --- a/Roles/Impostor/Blackmailer.cs +++ b/Roles/Impostor/Blackmailer.cs @@ -38,4 +38,10 @@ public class Blackmailer : RoleBase } public override bool IsEnable => playerIdList.Count > 0; + + public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting) + { + ForBlackmailer.Add(target.PlayerId); + return false; + } } \ No newline at end of file diff --git a/Roles/Impostor/BountyHunter.cs b/Roles/Impostor/BountyHunter.cs index 5cf1eeb6d..f8d60ab7f 100644 --- a/Roles/Impostor/BountyHunter.cs +++ b/Roles/Impostor/BountyHunter.cs @@ -1,6 +1,6 @@ +using Hazel; using System.Collections.Generic; using System.Linq; -using Hazel; using UnityEngine; using static TOHE.Translator; diff --git a/Roles/Impostor/Chronomancer.cs b/Roles/Impostor/Chronomancer.cs index 3209e2a97..d97b45115 100644 --- a/Roles/Impostor/Chronomancer.cs +++ b/Roles/Impostor/Chronomancer.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using static TOHE.Options; namespace TOHE.Roles.Impostor @@ -141,5 +141,10 @@ namespace TOHE.Roles.Impostor IsRampaging = false; SendRPC(); } + + public override void AfterMeetingTasks() + { + OnReportDeadBody(); + } } } \ No newline at end of file diff --git a/Roles/Impostor/Councillor.cs b/Roles/Impostor/Councillor.cs index 25130fe08..998746840 100644 --- a/Roles/Impostor/Councillor.cs +++ b/Roles/Impostor/Councillor.cs @@ -1,9 +1,9 @@ -using System; +using HarmonyLib; +using Hazel; +using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -using HarmonyLib; -using Hazel; using TOHE.Roles.Crewmate; using UnityEngine; using static TOHE.Translator; diff --git a/Roles/Impostor/Crewpostor.cs b/Roles/Impostor/Crewpostor.cs index d30be4a0d..4538da15a 100644 --- a/Roles/Impostor/Crewpostor.cs +++ b/Roles/Impostor/Crewpostor.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; -using Hazel; using UnityEngine; namespace TOHE.Roles.Impostor @@ -12,7 +12,7 @@ namespace TOHE.Roles.Impostor public static bool On; public override bool IsEnable => On; - public static void OnTaskComplete(PlayerControl player) + public override void OnTaskComplete(PlayerControl player, int completedTaskCount, int totalTaskCount) { if (!TasksDone.TryAdd(player.PlayerId, 0)) TasksDone[player.PlayerId]++; @@ -64,6 +64,11 @@ namespace TOHE.Roles.Impostor } } + public override bool CanUseKillButton(PlayerControl pc) + { + return false; + } + public static void SendRPC(byte cpID, int tasksDone) { if (PlayerControl.LocalPlayer.PlayerId == cpID) @@ -96,6 +101,7 @@ namespace TOHE.Roles.Impostor public override void Add(byte playerId) { On = true; + TasksDone[playerId] = 0; } } } \ No newline at end of file diff --git a/Roles/Impostor/Dazzler.cs b/Roles/Impostor/Dazzler.cs index 2b17e79bf..a99de98e6 100644 --- a/Roles/Impostor/Dazzler.cs +++ b/Roles/Impostor/Dazzler.cs @@ -1,6 +1,5 @@ -using System.Collections.Generic; -using System.Linq; using AmongUs.GameOptions; +using System.Collections.Generic; using TOHE.Roles.Neutral; using static TOHE.Options; using static TOHE.Translator; diff --git a/Roles/Impostor/Devourer.cs b/Roles/Impostor/Devourer.cs index f3fd8f201..8545274b1 100644 --- a/Roles/Impostor/Devourer.cs +++ b/Roles/Impostor/Devourer.cs @@ -1,6 +1,6 @@ +using AmongUs.GameOptions; using System.Collections.Generic; using System.Linq; -using AmongUs.GameOptions; using TOHE.Roles.Neutral; using static TOHE.Options; using static TOHE.Translator; @@ -18,7 +18,9 @@ namespace TOHE.Roles.Impostor private static OptionItem DefaultKillCooldown; private static OptionItem ReduceKillCooldown; private static OptionItem MinKillCooldown; + private static OptionItem ShapeshiftCooldown; + // private static OptionItem ShapeshiftDuration; public static OptionItem HideNameOfConsumedPlayer; diff --git a/Roles/Impostor/Duellist.cs b/Roles/Impostor/Duellist.cs index 8d07da7a5..13249725d 100644 --- a/Roles/Impostor/Duellist.cs +++ b/Roles/Impostor/Duellist.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; +using AmongUs.GameOptions; +using System.Collections.Generic; using TOHE.Roles.Crewmate; using TOHE.Roles.Neutral; using static TOHE.Options; @@ -87,4 +87,4 @@ namespace TOHE.Roles.Impostor } } } -} +} \ No newline at end of file diff --git a/Roles/Impostor/Escapee.cs b/Roles/Impostor/Escapee.cs index 5cbbb7a5e..e2a164463 100644 --- a/Roles/Impostor/Escapee.cs +++ b/Roles/Impostor/Escapee.cs @@ -1,5 +1,4 @@ using AmongUs.GameOptions; -using System.Collections.Generic; using TOHE.Modules; using UnityEngine; diff --git a/Roles/Impostor/EvilDiviner.cs b/Roles/Impostor/EvilDiviner.cs index 1f4a7a924..81ef456e2 100644 --- a/Roles/Impostor/EvilDiviner.cs +++ b/Roles/Impostor/EvilDiviner.cs @@ -1,5 +1,7 @@ +using AmongUs.GameOptions; using Hazel; using System.Collections.Generic; +using TOHE.Roles.Neutral; using static TOHE.Options; namespace TOHE.Roles.Impostor @@ -14,6 +16,11 @@ namespace TOHE.Roles.Impostor public static OptionItem EDAbilityUseGainWithEachKill; public List DivinationTarget = []; + private bool IsRitualist; + + private bool CanVent; + private bool HasImpVision; + private float KCD; public static void SetupCustomOption() { @@ -36,8 +43,38 @@ namespace TOHE.Roles.Impostor public override void Add(byte playerId) { playerIdList.Add(playerId); - playerId.SetAbilityUseLimit(DivinationMaxCount.GetInt()); DivinationTarget = []; + + IsRitualist = Main.PlayerStates[playerId].MainRole == CustomRoles.Ritualist; + playerId.SetAbilityUseLimit(IsRitualist ? Ritualist.RitualMaxCount.GetInt() : DivinationMaxCount.GetInt()); + if (IsRitualist) + { + KCD = Ritualist.KillCooldown.GetFloat(); + CanVent = Ritualist.CanVent.GetBool(); + HasImpVision = Ritualist.HasImpostorVision.GetBool(); + } + else + { + KCD = KillCooldown.GetFloat(); + CanVent = true; + HasImpVision = true; + } + + if (!AmongUsClient.Instance.AmHost || !IsRitualist) return; + if (!Main.ResetCamPlayerList.Contains(playerId)) + { + Main.ResetCamPlayerList.Add(playerId); + } + } + + public override bool CanUseImpostorVentButton(PlayerControl pc) + { + return CanVent; + } + + public override void ApplyGameOptions(IGameOptions opt, byte playerId) + { + opt.SetVision(HasImpVision); } static void SendRPC(byte playerId, byte targetId) @@ -58,7 +95,7 @@ namespace TOHE.Roles.Impostor public override void SetKillCooldown(byte id) { - Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + Main.AllPlayerKillCooldown[id] = KCD; } public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) diff --git a/Roles/Impostor/EvilTracker.cs b/Roles/Impostor/EvilTracker.cs index 7c3e033fc..39f0830b5 100644 --- a/Roles/Impostor/EvilTracker.cs +++ b/Roles/Impostor/EvilTracker.cs @@ -1,9 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; using AmongUs.GameOptions; using Hazel; using Il2CppSystem.Text; +using System; +using System.Collections.Generic; +using System.Linq; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -177,7 +177,7 @@ public class EvilTracker : RoleBase (Main.PlayerStates[trackerId].Role as EvilTracker)?.SetTarget(trackerId, targetId); } - public static string GetMarker(byte playerId) => Main.PlayerStates[playerId].Role is not EvilTracker et ? null : et.CanTarget(playerId) ? Utils.ColorString(Palette.ImpostorRed.ShadeColor(0.5f), "◁") : string.Empty; + public override string GetProgressText(byte playerId, bool comms) => Main.PlayerStates[playerId].Role is not EvilTracker et ? null : et.CanTarget(playerId) ? Utils.ColorString(Palette.ImpostorRed.ShadeColor(0.5f), "◁") : string.Empty; public static string GetTargetMark(PlayerControl seer, PlayerControl target) => Main.PlayerStates[seer.PlayerId].Role is not EvilTracker et ? string.Empty : et.Target == target.PlayerId ? Utils.ColorString(Palette.ImpostorRed, "◀") : string.Empty; public static string GetTargetArrow(PlayerControl seer, PlayerControl target) diff --git a/Roles/Impostor/FireWorks.cs b/Roles/Impostor/FireWorks.cs index 2bad68b36..de4ff90c4 100644 --- a/Roles/Impostor/FireWorks.cs +++ b/Roles/Impostor/FireWorks.cs @@ -1,6 +1,6 @@ +using Hazel; using System; using System.Collections.Generic; -using Hazel; using TOHE.Roles.Crewmate; using TOHE.Roles.Neutral; using UnityEngine; diff --git a/Roles/Impostor/Gambler.cs b/Roles/Impostor/Gambler.cs index 67dd7ce07..bb9f8a307 100644 --- a/Roles/Impostor/Gambler.cs +++ b/Roles/Impostor/Gambler.cs @@ -95,6 +95,11 @@ namespace TOHE.Roles.Impostor public override bool IsEnable => playerIdList.Count > 0; + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = Gambler.KillCooldown.GetFloat(); + } + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (killer == null) return false; diff --git a/Roles/Impostor/Gangster.cs b/Roles/Impostor/Gangster.cs index 4bc2536e0..f1ba03162 100644 --- a/Roles/Impostor/Gangster.cs +++ b/Roles/Impostor/Gangster.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using UnityEngine; using static TOHE.Translator; namespace TOHE.Roles.Impostor; @@ -159,8 +158,6 @@ public class Gangster : RoleBase return false; } - public static string GetRecruitLimit(byte playerId) => Utils.ColorString(CanRecruit(playerId) ? Utils.GetRoleColor(CustomRoles.Gangster).ShadeColor(0.25f) : Color.gray, $"({playerId.GetAbilityUseLimit()})"); - public static bool CanBeMadmate(PlayerControl pc) { return pc != null && pc.GetCustomRole().IsCrewmate() && !pc.Is(CustomRoles.Madmate) diff --git a/Roles/Impostor/Godfather.cs b/Roles/Impostor/Godfather.cs index 5490c35e9..2e2b3bf65 100644 --- a/Roles/Impostor/Godfather.cs +++ b/Roles/Impostor/Godfather.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TOHE.Roles.Impostor +namespace TOHE.Roles.Impostor { internal class Godfather : RoleBase { @@ -22,4 +16,4 @@ namespace TOHE.Roles.Impostor On = false; } } -} +} \ No newline at end of file diff --git a/Roles/Impostor/Greedier.cs b/Roles/Impostor/Greedier.cs index 35e38f3b9..c5b0bf297 100644 --- a/Roles/Impostor/Greedier.cs +++ b/Roles/Impostor/Greedier.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; +using System.Linq; using TOHE.Roles.Neutral; namespace TOHE.Roles.Impostor; diff --git a/Roles/Impostor/Hacker.cs b/Roles/Impostor/Hacker.cs index a1402ea22..a8b0a0ec7 100644 --- a/Roles/Impostor/Hacker.cs +++ b/Roles/Impostor/Hacker.cs @@ -48,8 +48,6 @@ public class Hacker : RoleBase AURoleOptions.ShapeshifterDuration = 1f; } - public static string GetHackLimit(byte playerId) => Utils.GetAbilityUseLimitDisplay(playerId); - public override void SetButtonTexts(HudManager __instance, byte playerId) { if (playerId.GetAbilityUseLimit() >= 1) diff --git a/Roles/Impostor/Hangman.cs b/Roles/Impostor/Hangman.cs index c0e101b95..04f50aacc 100644 --- a/Roles/Impostor/Hangman.cs +++ b/Roles/Impostor/Hangman.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; +using AmongUs.GameOptions; +using System.Collections.Generic; using TOHE.Roles.Crewmate; using static TOHE.Options; @@ -73,6 +73,7 @@ public class Hangman : RoleBase killer.SetKillCooldown(time: KCD.GetFloat()); return false; } + return true; } } \ No newline at end of file diff --git a/Roles/Impostor/Hitman.cs b/Roles/Impostor/Hitman.cs index 37bf2ffae..618435ac3 100644 --- a/Roles/Impostor/Hitman.cs +++ b/Roles/Impostor/Hitman.cs @@ -43,6 +43,11 @@ namespace TOHE.Roles.Impostor public override bool IsEnable => playerIdList.Count > 0; + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + } + void SendRPC() { if (!DoRPC) return; @@ -72,7 +77,18 @@ namespace TOHE.Roles.Impostor return true; } - public override void OnReportDeadBody(PlayerControl reporter, PlayerControl _) + public static void CheckAndResetTargets() + { + foreach (var id in playerIdList) + { + if (Main.PlayerStates[id].Role is Hitman { IsEnable: true } hm) + { + hm.OnReportDeadBody(); + } + } + } + + public override void OnReportDeadBody() { var target = GetPlayerById(TargetId); if (!target.IsAlive() || target.Data.Disconnected) diff --git a/Roles/Impostor/Librarian.cs b/Roles/Impostor/Librarian.cs index 142a5db16..12898d876 100644 --- a/Roles/Impostor/Librarian.cs +++ b/Roles/Impostor/Librarian.cs @@ -1,7 +1,6 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; diff --git a/Roles/Impostor/Mafioso.cs b/Roles/Impostor/Mafioso.cs index 89b552fe3..42e6745c3 100644 --- a/Roles/Impostor/Mafioso.cs +++ b/Roles/Impostor/Mafioso.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System; +using System.Collections.Generic; using static TOHE.Options; using static TOHE.Translator; using static TOHE.Utils; diff --git a/Roles/Impostor/Mastermind.cs b/Roles/Impostor/Mastermind.cs index a2cf4e867..9c6c37826 100644 --- a/Roles/Impostor/Mastermind.cs +++ b/Roles/Impostor/Mastermind.cs @@ -56,6 +56,11 @@ namespace TOHE.Roles.Impostor public override bool IsEnable => MastermindId != byte.MaxValue || Randomizer.IsEnable; + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = Mastermind.KillCooldown.GetFloat(); + } + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (!IsEnable) return false; diff --git a/Roles/Impostor/QuickShooter.cs b/Roles/Impostor/QuickShooter.cs index 2394ebf24..f144fc8a9 100644 --- a/Roles/Impostor/QuickShooter.cs +++ b/Roles/Impostor/QuickShooter.cs @@ -1,6 +1,6 @@ -using System; +using Hazel; +using System; using System.Collections.Generic; -using Hazel; using UnityEngine; namespace TOHE.Roles.Impostor; diff --git a/Roles/Impostor/RiftMaker.cs b/Roles/Impostor/RiftMaker.cs index 7bc4a8ca6..a3b6e98dc 100644 --- a/Roles/Impostor/RiftMaker.cs +++ b/Roles/Impostor/RiftMaker.cs @@ -42,6 +42,11 @@ namespace TOHE.Roles.Impostor public override bool IsEnable => playerIdList.Count > 0; + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = RiftMaker.KillCooldown.GetFloat(); + } + public override void OnFixedUpdate(PlayerControl player) { if (!GameStates.IsInTask) return; @@ -99,7 +104,7 @@ namespace TOHE.Roles.Impostor Marks.Clear(); player.Notify(GetString("MarksCleared")); - _ = new LateTask(() => { player.MyPhysics?.RpcBootFromVent(ventId); }, 0.5f, "RiftMaker-ResetMarks.RpcBootFromVent"); + player.MyPhysics?.RpcBootFromVent(vent.Id); } public override bool OnShapeshift(PlayerControl player, PlayerControl target, bool shapeshifting) diff --git a/Roles/Impostor/Sans.cs b/Roles/Impostor/Sans.cs index e0105cdff..db0651de6 100644 --- a/Roles/Impostor/Sans.cs +++ b/Roles/Impostor/Sans.cs @@ -1,6 +1,6 @@ -using System; +using AmongUs.GameOptions; +using System; using System.Collections.Generic; -using AmongUs.GameOptions; using TOHE.Roles.Neutral; using static TOHE.Options; diff --git a/Roles/Impostor/Sapper.cs b/Roles/Impostor/Sapper.cs index 1fd1f14b7..f1df4f0a1 100644 --- a/Roles/Impostor/Sapper.cs +++ b/Roles/Impostor/Sapper.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; +using AmongUs.GameOptions; +using System.Collections.Generic; using System.Linq; using System.Text; -using AmongUs.GameOptions; using TOHE.Roles.Neutral; using UnityEngine; using static TOHE.Options; @@ -49,6 +49,11 @@ namespace TOHE.Roles.Impostor AURoleOptions.ShapeshifterDuration = 1f; } + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = 300f; + } + public override bool IsEnable => playerIdList.Count > 0; public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting) @@ -56,6 +61,16 @@ namespace TOHE.Roles.Impostor return PlaceBomb(shapeshifter); } + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) + { + return false; + } + + public override bool CanUseKillButton(PlayerControl pc) + { + return false; + } + public override void OnPet(PlayerControl pc) { PlaceBomb(pc); diff --git a/Roles/Impostor/Sniper.cs b/Roles/Impostor/Sniper.cs index 8786d4567..290fc23da 100644 --- a/Roles/Impostor/Sniper.cs +++ b/Roles/Impostor/Sniper.cs @@ -1,6 +1,6 @@ +using Hazel; using System.Collections.Generic; using System.Linq; -using Hazel; using TOHE.Modules; using TOHE.Roles.Crewmate; using TOHE.Roles.Neutral; diff --git a/Roles/Impostor/Stealth.cs b/Roles/Impostor/Stealth.cs index 1041fdd5b..ccc666451 100644 --- a/Roles/Impostor/Stealth.cs +++ b/Roles/Impostor/Stealth.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; -using Hazel; using UnityEngine; namespace TOHE.Roles.Impostor diff --git a/Roles/Impostor/Swooper.cs b/Roles/Impostor/Swooper.cs index acf664a9c..a99786856 100644 --- a/Roles/Impostor/Swooper.cs +++ b/Roles/Impostor/Swooper.cs @@ -1,8 +1,8 @@ -using System; +using AmongUs.GameOptions; using Hazel; +using System; using System.Collections.Generic; using System.Text; -using AmongUs.GameOptions; using TOHE.Roles.Crewmate; using TOHE.Roles.Neutral; using static TOHE.Options; @@ -223,6 +223,7 @@ public class Swooper : RoleBase pc?.MyPhysics?.RpcBootFromVent(vent.Id); pc.Notify(GetString("SwooperInvisStateOut")); } + public static string GetHudText(PlayerControl pc) { if (pc == null || !GameStates.IsInTask || !PlayerControl.LocalPlayer.IsAlive()) return string.Empty; @@ -243,6 +244,7 @@ public class Swooper : RoleBase { str.Append(GetString("SwooperCanVent")); } + return str.ToString(); } diff --git a/Roles/Impostor/Underdog.cs b/Roles/Impostor/Underdog.cs index 2c6a3bdee..26d0964d9 100644 --- a/Roles/Impostor/Underdog.cs +++ b/Roles/Impostor/Underdog.cs @@ -1,11 +1,4 @@ -using MS.Internal.Xml.XPath; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TOHE.Roles.Impostor +namespace TOHE.Roles.Impostor { internal class Underdog : RoleBase { @@ -32,4 +25,4 @@ namespace TOHE.Roles.Impostor SetKillCooldown(killer.PlayerId); } } -} +} \ No newline at end of file diff --git a/Roles/Impostor/Undertaker.cs b/Roles/Impostor/Undertaker.cs index 969c7630f..b483e4822 100644 --- a/Roles/Impostor/Undertaker.cs +++ b/Roles/Impostor/Undertaker.cs @@ -1,11 +1,4 @@ -using System.Collections.Generic; -using Hazel; -using TOHE.Modules; -using TOHE.Roles.Crewmate; -using TOHE.Roles.Neutral; -using UnityEngine; -using static TOHE.Options; -using static TOHE.Translator; +using static TOHE.Options; namespace TOHE.Roles.Impostor; diff --git a/Roles/Impostor/Vampire.cs b/Roles/Impostor/Vampire.cs index 3e4ffad09..c44ef11a0 100644 --- a/Roles/Impostor/Vampire.cs +++ b/Roles/Impostor/Vampire.cs @@ -98,6 +98,7 @@ public class Vampire : RoleBase { BittenPlayers.Add(target.PlayerId, new(killer.PlayerId, 0f)); } + return false; } @@ -108,7 +109,7 @@ public class Vampire : RoleBase var vampireID = vampire.PlayerId; if (!IsThisRole(vampire.PlayerId)) return; - List targetList = [..BittenPlayers.Where(b => b.Value.VampireId == vampireID).Select(b => b.Key)]; + List targetList = [.. BittenPlayers.Where(b => b.Value.VampireId == vampireID).Select(b => b.Key)]; foreach (byte targetId in targetList.ToArray()) { @@ -126,6 +127,7 @@ public class Vampire : RoleBase } } } + public static void KillBitten(PlayerControl vampire, PlayerControl target, bool isButton = false) { if (vampire == null || target == null || target.Data.Disconnected) return; @@ -150,6 +152,7 @@ public class Vampire : RoleBase var vampire = Utils.GetPlayerById(BittenPlayers[targetId].VampireId); KillBitten(vampire, target); } + BittenPlayers.Clear(); } @@ -157,4 +160,4 @@ public class Vampire : RoleBase { hud.KillButton.OverrideText(GetString("VampireBiteButtonText")); } -} +} \ No newline at end of file diff --git a/Roles/Impostor/Wildling.cs b/Roles/Impostor/Wildling.cs index ca015cf3d..7e85947c4 100644 --- a/Roles/Impostor/Wildling.cs +++ b/Roles/Impostor/Wildling.cs @@ -1,8 +1,8 @@ +using AmongUs.GameOptions; +using Hazel; using System; using System.Collections.Generic; using System.Text; -using AmongUs.GameOptions; -using Hazel; using TOHE.Roles.Neutral; using static TOHE.Options; diff --git a/Roles/Neutral/Agitater.cs b/Roles/Neutral/Agitater.cs index 74ba5690a..d0d7af79e 100644 --- a/Roles/Neutral/Agitater.cs +++ b/Roles/Neutral/Agitater.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; +using System.Linq; using TOHE.Roles.Crewmate; using UnityEngine; using static TOHE.Translator; @@ -106,7 +106,6 @@ public class Agitater : RoleBase Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} bombed {pc.GetNameWithRole().RemoveHtmlTags()}, bomb cd complete", "Agitater"); ResetBomb(); } - } }, BombExplodeCooldown.GetFloat(), "AgitaterBombKill"); return false; @@ -182,6 +181,7 @@ public class Agitater : RoleBase ResetBomb(); return; } + LastBombedPlayer = CurrentBombedPlayer; CurrentBombedPlayer = target.PlayerId; CurrentBombedPlayerTime = now; @@ -213,4 +213,4 @@ public class Agitater : RoleBase at.CurrentBombedPlayer = reader.ReadByte(); at.LastBombedPlayer = reader.ReadByte(); } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Amnesiac.cs b/Roles/Neutral/Amnesiac.cs index 3dd4182a6..f92438d54 100644 --- a/Roles/Neutral/Amnesiac.cs +++ b/Roles/Neutral/Amnesiac.cs @@ -1,7 +1,7 @@ -using System; -using System.Collections.Generic; using AmongUs.GameOptions; using Hazel; +using System; +using System.Collections.Generic; using static TOHE.Options; using static TOHE.Translator; @@ -60,9 +60,11 @@ public class Amnesiac : RoleBase writer.Write(RememberLimit); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) => RememberLimit = reader.ReadInt32(); public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = RememberLimit >= 1 ? RememberCooldown.GetFloat() : 300f; public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead && RememberLimit >= 1; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { @@ -124,8 +126,6 @@ public class Amnesiac : RoleBase Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: killer); - Utils.AddRoles(killer.PlayerId, role); - killer.ResetKillCooldown(); killer.SetKillCooldown(); @@ -134,10 +134,11 @@ public class Amnesiac : RoleBase return false; } + public static bool KnowRole(PlayerControl player, PlayerControl target) { if (player.IsNeutralKiller() && target.IsNeutralKiller() && player.GetCustomRole() == target.GetCustomRole()) return true; if (player.Is(CustomRoles.Refugee) && target.Is(CustomRoleTypes.Impostor)) return true; return player.Is(CustomRoleTypes.Impostor) && target.Is(CustomRoles.Refugee); } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Arsonist.cs b/Roles/Neutral/Arsonist.cs index 6e8ba3b90..3ac268595 100644 --- a/Roles/Neutral/Arsonist.cs +++ b/Roles/Neutral/Arsonist.cs @@ -49,69 +49,92 @@ namespace TOHE.Roles.Neutral return Utils.ColorString(Utils.GetRoleColor(CustomRoles.Arsonist).ShadeColor(0.25f), !Options.ArsonistCanIgniteAnytime.GetBool() ? $"- {doused.Item1}/{doused.Item2}" : $"- {doused.Item1}/{Options.ArsonistMaxPlayersToIgnite.GetInt()}"); } + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) + { + killer.SetKillCooldown(Options.ArsonistDouseTime.GetFloat()); + if (!Main.isDoused[(killer.PlayerId, target.PlayerId)] && !Main.ArsonistTimer.ContainsKey(killer.PlayerId)) + { + Main.ArsonistTimer.Add(killer.PlayerId, (target, 0f)); + Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target, ForceLoop: true); + RPC.SetCurrentDousingTarget(killer.PlayerId, target.PlayerId); + } + + return false; + } + + public override void OnPet(PlayerControl pc) + { + Ignite(pc.MyPhysics); + } + public override void OnCoEnterVent(PlayerPhysics physics, int ventId) { if (AmongUsClient.Instance.IsGameStarted) { - if (physics.myPlayer.IsDouseDone()) + Ignite(physics); + } + } + + private static void Ignite(PlayerPhysics physics) + { + if (physics.myPlayer.IsDouseDone()) + { + CustomSoundsManager.RPCPlayCustomSoundAll("Boom"); + foreach (PlayerControl pc in Main.AllAlivePlayerControls) { - CustomSoundsManager.RPCPlayCustomSoundAll("Boom"); - foreach (PlayerControl pc in Main.AllAlivePlayerControls) + if (pc != physics.myPlayer) { - if (pc != physics.myPlayer) - { - pc.Suicide(PlayerState.DeathReason.Torched, physics.myPlayer); - } + pc.Suicide(PlayerState.DeathReason.Torched, physics.myPlayer); } - - foreach (PlayerControl pc in Main.AllPlayerControls) - { - pc.KillFlash(); - } - - CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); //焼殺で勝利した人も勝利させる - CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId); - return; } - if (Options.ArsonistCanIgniteAnytime.GetBool()) + foreach (PlayerControl pc in Main.AllPlayerControls) { - var douseCount = Utils.GetDousedPlayerCount(physics.myPlayer.PlayerId).Item1; - if (douseCount >= Options.ArsonistMinPlayersToIgnite.GetInt()) // Don't check for max, since the player would not be able to ignite at all if they somehow get more players doused than the max + pc.KillFlash(); + } + + CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); //焼殺で勝利した人も勝利させる + CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId); + return; + } + + if (Options.ArsonistCanIgniteAnytime.GetBool()) + { + var douseCount = Utils.GetDousedPlayerCount(physics.myPlayer.PlayerId).Item1; + if (douseCount >= Options.ArsonistMinPlayersToIgnite.GetInt()) // Don't check for max, since the player would not be able to ignite at all if they somehow get more players doused than the max + { + if (douseCount > Options.ArsonistMaxPlayersToIgnite.GetInt()) Logger.Warn("Arsonist Ignited with more players doused than the maximum amount in the settings", "Arsonist Ignite"); + foreach (PlayerControl pc in Main.AllAlivePlayerControls) { - if (douseCount > Options.ArsonistMaxPlayersToIgnite.GetInt()) Logger.Warn("Arsonist Ignited with more players doused than the maximum amount in the settings", "Arsonist Ignite"); - foreach (PlayerControl pc in Main.AllAlivePlayerControls) - { - if (!physics.myPlayer.IsDousedPlayer(pc)) - continue; - pc.KillFlash(); - pc.Suicide(PlayerState.DeathReason.Torched, physics.myPlayer); - } + if (!physics.myPlayer.IsDousedPlayer(pc)) + continue; + pc.KillFlash(); + pc.Suicide(PlayerState.DeathReason.Torched, physics.myPlayer); + } - var apc = Main.AllAlivePlayerControls.Length; - switch (apc) + var apc = Main.AllAlivePlayerControls.Length; + switch (apc) + { + case 1: + CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); + CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId); + break; + case 2: { - case 1: - CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); - CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId); - break; - case 2: + foreach (var x in Main.AllAlivePlayerControls.Where(p => p.PlayerId != physics.myPlayer.PlayerId).ToArray()) { - foreach (var x in Main.AllAlivePlayerControls.Where(p => p.PlayerId != physics.myPlayer.PlayerId).ToArray()) + if (!x.GetCustomRole().IsImpostor() && !x.GetCustomRole().IsNeutralKilling()) { - if (!x.GetCustomRole().IsImpostor() && !x.GetCustomRole().IsNeutralKilling()) - { - CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); - CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId); - } + CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist); + CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId); } - - break; } + + break; } } } } } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Bandit.cs b/Roles/Neutral/Bandit.cs index 18822dea2..c7e48fdbf 100644 --- a/Roles/Neutral/Bandit.cs +++ b/Roles/Neutral/Bandit.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; @@ -61,8 +61,9 @@ public class Bandit : RoleBase public override bool IsEnable => On; public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); - private static void SendRPC(byte playerId/*, bool isTargetList = false*/) + private static void SendRPC(byte playerId /*, bool isTargetList = false*/) { if (!On || !Utils.DoRPC) return; MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetBanditStealLimit, SendOption.Reliable); @@ -104,6 +105,7 @@ public class Bandit : RoleBase Logger.Info("No stealable addons found on the target.", "Bandit"); return null; } + var rand = IRandom.Instance; var addon = AllSubRoles[rand.Next(0, AllSubRoles.Count)]; return addon; @@ -139,6 +141,7 @@ public class Bandit : RoleBase Targets[killer.PlayerId][target.PlayerId] = (CustomRoles)SelectedAddOn; Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} will steal {SelectedAddOn} addon from {target.GetNameWithRole().RemoveHtmlTags()} after meeting starts", "Bandit"); } + TotalSteals[killer.PlayerId]++; SendRPC(killer.PlayerId); Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target, ForceLoop: true); @@ -172,6 +175,7 @@ public class Bandit : RoleBase Logger.Info($"Successfully Added {role} addon to {banditpc.GetNameWithRole().RemoveHtmlTags()}", "Bandit"); Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: banditpc); } + Targets[banditId].Clear(); } } diff --git a/Roles/Neutral/Bubble.cs b/Roles/Neutral/Bubble.cs index d17a38bf4..33ca7346f 100644 --- a/Roles/Neutral/Bubble.cs +++ b/Roles/Neutral/Bubble.cs @@ -1,8 +1,8 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using HarmonyLib; using Hazel; +using System.Collections.Generic; +using System.Linq; using UnityEngine; using static TOHE.Options; using static TOHE.Utils; @@ -67,6 +67,7 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => BubbleId != byte.MaxValue; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); void SendRPC(byte id = byte.MaxValue, bool remove = false, bool clear = false) { @@ -77,6 +78,7 @@ namespace TOHE.Roles.Neutral writer.Write(id); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { bool remove = reader.ReadBoolean(); @@ -150,10 +152,11 @@ namespace TOHE.Roles.Neutral EncasedPlayers.Clear(); SendRPC(clear: true); } + public static string GetEncasedPlayerSuffix(PlayerControl target) { if (target == null || !EncasedPlayers.TryGetValue(target.PlayerId, out var ts) || (ts + NotifyDelay.GetInt() >= TimeStamp)) return string.Empty; return ColorString(GetRoleColor(CustomRoles.Bubble), $"{ExplodeDelay.GetInt() - (TimeStamp - ts) + 1}s"); } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Collector.cs b/Roles/Neutral/Collector.cs index ce6cd630c..378018113 100644 --- a/Roles/Neutral/Collector.cs +++ b/Roles/Neutral/Collector.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; -using Hazel; namespace TOHE.Roles.Neutral; @@ -42,6 +42,7 @@ public class Collector : RoleBase writer.Write(CollectVote[playerId]); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte PlayerId = reader.ReadByte(); @@ -56,6 +57,7 @@ public class Collector : RoleBase int CollectNum = CollectorCollectAmount.GetInt(); return Utils.ColorString(Utils.GetRoleColor(CustomRoles.Collector).ShadeColor(0.25f), $"({VoteAmount}/{CollectNum})"); } + public static bool CollectorWin(bool check = true) { var pc = Main.AllPlayerControls.Where(x => x.Is(CustomRoles.Collector) && x.IsAlive() && CollectDone(x)).ToArray(); @@ -66,8 +68,10 @@ public class Collector : RoleBase foreach (var winner in pc) CustomWinnerHolder.WinnerIds.Add(winner.PlayerId); return true; } + return false; } + public static bool CollectDone(PlayerControl player) { if (player.Is(CustomRoles.Collector)) @@ -77,14 +81,17 @@ public class Collector : RoleBase int CollectNum = CollectorCollectAmount.GetInt(); if (VoteAmount >= CollectNum) return true; } + return false; } - public static void CollectorVotes(PlayerControl target, PlayerVoteArea ps)//集票者投票给谁 + + public static void CollectorVotes(PlayerControl target, PlayerVoteArea ps) //集票者投票给谁 { if (CheckForEndVotingPatch.CheckRole(ps.TargetPlayerId, CustomRoles.Collector)) CollectorVoteFor.TryAdd(target.PlayerId, ps.TargetPlayerId); } - public static void CollectAmount(Dictionary VotingData, MeetingHud __instance)//得到集票者收集到的票 + + public static void CollectAmount(Dictionary VotingData, MeetingHud __instance) //得到集票者收集到的票 { foreach (PlayerVoteArea pva in __instance.playerStates.ToArray()) { @@ -102,4 +109,4 @@ public class Collector : RoleBase } } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/DarkHide.cs b/Roles/Neutral/DarkHide.cs index e44257b62..58462c004 100644 --- a/Roles/Neutral/DarkHide.cs +++ b/Roles/Neutral/DarkHide.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; using InnerNet; +using System.Collections.Generic; namespace TOHE.Roles.Neutral; @@ -29,7 +29,6 @@ public class DarkHide : RoleBase HasImpostorVision = BooleanOptionItem.Create(Id + 11, "ImpostorVision", false, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.DarkHide]); CanCountNeutralKiller = BooleanOptionItem.Create(Id + 12, "CanCountNeutralKiller", false, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.DarkHide]); SnatchesWin = BooleanOptionItem.Create(Id + 13, "SnatchesWin", false, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.DarkHide]); - } public override void Init() @@ -73,6 +72,7 @@ public class DarkHide : RoleBase public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = CurrentKillCooldown; public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead; + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); @@ -105,5 +105,4 @@ public class DarkHide : RoleBase return true; } - -} +} \ No newline at end of file diff --git a/Roles/Neutral/Doomsayer.cs b/Roles/Neutral/Doomsayer.cs index 605640e8c..b277e2c4b 100644 --- a/Roles/Neutral/Doomsayer.cs +++ b/Roles/Neutral/Doomsayer.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using UnityEngine; namespace TOHE.Roles.Neutral; @@ -83,17 +83,20 @@ public class Doomsayer : RoleBase writer.Write(player.PlayerId); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte DoomsayerId = reader.ReadByte(); GuessingToWin[DoomsayerId]++; } + public static (int, int) GuessedPlayerCount(byte doomsayerId) { int doomsayerguess = GuessingToWin[doomsayerId], GuessesToWin = DoomsayerAmountOfGuessesToWin.GetInt(); return (doomsayerguess, GuessesToWin); } + public static void CheckCountGuess(PlayerControl doomsayer) { if (!(GuessingToWin[doomsayer.PlayerId] >= DoomsayerAmountOfGuessesToWin.GetInt())) return; diff --git a/Roles/Neutral/Doppelganger.cs b/Roles/Neutral/Doppelganger.cs index 2b5b532bb..b33fb4b52 100644 --- a/Roles/Neutral/Doppelganger.cs +++ b/Roles/Neutral/Doppelganger.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; -using Hazel; +using Hazel; +using System.Collections.Generic; using TOHE.Roles.Impostor; using UnityEngine; using static TOHE.Options; @@ -67,6 +67,7 @@ public class Doppelganger : RoleBase } public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; //overloading public static GameData.PlayerOutfit Set(GameData.PlayerOutfit instance, string playerName, int colorId, string hatId, string skinId, string visorId, string petId, string nameplateId) @@ -89,29 +90,29 @@ public class Doppelganger : RoleBase pc.SetName(newOutfit.PlayerName); sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.SetName) .Write(newOutfit.PlayerName) - .EndRpc(); + .EndRpc(); //pc.RpcSetName(newOutfit.PlayerName); Main.AllPlayerNames[pc.PlayerId] = newOutfit.PlayerName; pc.SetColor(newOutfit.ColorId); sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.SetColor) .Write(newOutfit.ColorId) - .EndRpc(); + .EndRpc(); pc.SetHat(newOutfit.HatId, newOutfit.ColorId); sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.SetHatStr) .Write(newOutfit.HatId) - .EndRpc(); + .EndRpc(); pc.SetSkin(newOutfit.SkinId, newOutfit.ColorId); sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.SetSkinStr) .Write(newOutfit.SkinId) - .EndRpc(); + .EndRpc(); pc.SetVisor(newOutfit.VisorId, newOutfit.ColorId); sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.SetVisorStr) .Write(newOutfit.VisorId) - .EndRpc(); + .EndRpc(); pc.SetPet(newOutfit.PetId); sender.AutoStartRpc(pc.NetId, (byte)RpcCalls.SetPetStr) @@ -135,6 +136,7 @@ public class Doppelganger : RoleBase Logger.Info("Target was shapeshifting", "Doppelganger"); return true; } + if (TotalSteals[killer.PlayerId] >= MaxSteals.GetInt()) { TotalSteals[killer.PlayerId] = MaxSteals.GetInt(); diff --git a/Roles/Neutral/Eclipse.cs b/Roles/Neutral/Eclipse.cs index fd58a51c5..16999cff0 100644 --- a/Roles/Neutral/Eclipse.cs +++ b/Roles/Neutral/Eclipse.cs @@ -1,6 +1,6 @@ +using AmongUs.GameOptions; using System; using System.Collections.Generic; -using AmongUs.GameOptions; using static TOHE.Options; namespace TOHE.Roles.Neutral; @@ -52,6 +52,7 @@ public class Eclipse : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public override void ApplyGameOptions(IGameOptions opt, byte id) { @@ -73,4 +74,4 @@ public class Eclipse : RoleBase pc.MarkDirtySettings(); } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Enderman.cs b/Roles/Neutral/Enderman.cs index 2b50708f5..709123845 100644 --- a/Roles/Neutral/Enderman.cs +++ b/Roles/Neutral/Enderman.cs @@ -50,6 +50,8 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => EndermanId != byte.MaxValue; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(true); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => true; public override void OnPet(PlayerControl pc) { diff --git a/Roles/Neutral/Executioner.cs b/Roles/Neutral/Executioner.cs index 1266f3850..39ce76fe8 100644 --- a/Roles/Neutral/Executioner.cs +++ b/Roles/Neutral/Executioner.cs @@ -1,8 +1,8 @@ +using HarmonyLib; +using Hazel; using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; -using Hazel; using static TOHE.Options; namespace TOHE.Roles.Neutral; diff --git a/Roles/Neutral/FFF.cs b/Roles/Neutral/FFF.cs index 9f0eb0926..2983f8031 100644 --- a/Roles/Neutral/FFF.cs +++ b/Roles/Neutral/FFF.cs @@ -59,6 +59,7 @@ namespace TOHE.Roles.Neutral } public override bool IsEnable => On; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { diff --git a/Roles/Neutral/Gamer.cs b/Roles/Neutral/Gamer.cs index 48a5b83cf..0be40b937 100644 --- a/Roles/Neutral/Gamer.cs +++ b/Roles/Neutral/Gamer.cs @@ -1,8 +1,9 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; + namespace TOHE.Roles.Neutral; public class Gamer : RoleBase @@ -62,6 +63,7 @@ public class Gamer : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); void SendRPC(byte playerId) { @@ -71,6 +73,7 @@ public class Gamer : RoleBase writer.Write(GamerHealth.TryGetValue(playerId, out int value) ? value : PlayerHealth[playerId]); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte PlayerId = reader.ReadByte(); @@ -125,6 +128,7 @@ public class Gamer : RoleBase Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} 对玩家 {target.GetNameWithRole().RemoveHtmlTags()} 造成了 {SelfDamage.GetInt()} 点伤害", "Gamer"); return false; } + public static string TargetMark(PlayerControl seer, PlayerControl target) { if (!seer.IsAlive()) return string.Empty; @@ -139,11 +143,15 @@ public class Gamer : RoleBase return GetValue && value > 0 ? Utils.ColorString(GetColor(value), $"【{value}/{HealthMax.GetInt()}】") : string.Empty; } } + private static Color32 GetColor(float Health, bool self = false) { var x = (int)(Health / (self ? SelfHealthMax.GetInt() : HealthMax.GetInt()) * 10 * 50); - int R = 255; int G = 255; int B = 0; - if (x > 255) R -= x - 255; else G = x; + int R = 255; + int G = 255; + int B = 0; + if (x > 255) R -= x - 255; + else G = x; return new Color32((byte)R, (byte)G, (byte)B, byte.MaxValue); } } \ No newline at end of file diff --git a/Roles/Neutral/Glitch.cs b/Roles/Neutral/Glitch.cs index 99dac8462..6d0f183c8 100644 --- a/Roles/Neutral/Glitch.cs +++ b/Roles/Neutral/Glitch.cs @@ -1,9 +1,9 @@ +using AmongUs.GameOptions; +using Hazel; using System; using System.Collections.Generic; using System.Linq; using System.Text; -using AmongUs.GameOptions; -using Hazel; using static TOHE.Options; namespace TOHE.Roles.Neutral; @@ -91,6 +91,8 @@ public class Glitch : RoleBase } public override bool IsEnable => playerIdList.Count > 0; + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => true; void SendRPCSyncTimers() { @@ -103,6 +105,7 @@ public class Glitch : RoleBase writer.Write(KCDTimer); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPCSyncTimers(MessageReader reader) { byte id = reader.ReadByte(); @@ -154,16 +157,16 @@ public class Glitch : RoleBase if (killer == null || target == null || (KCDTimer > 0 && HackCDTimer > 0)) return false; if (killer.CheckDoubleTrigger(target, () => - { - if (HackCDTimer <= 0) { - Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); - HackCDTimer = HackCooldown.GetInt(); - hackedIdList.TryAdd(target.PlayerId, Utils.TimeStamp); - LastHack = Utils.TimeStamp; - SendRPCSyncTimers(); - } - })) + if (HackCDTimer <= 0) + { + Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); + HackCDTimer = HackCooldown.GetInt(); + hackedIdList.TryAdd(target.PlayerId, Utils.TimeStamp); + LastHack = Utils.TimeStamp; + SendRPCSyncTimers(); + } + })) { if (KCDTimer > 0) return false; LastKill = Utils.TimeStamp; @@ -210,10 +213,18 @@ public class Glitch : RoleBase if (MimicDurTimer > 0) { - try { MimicDurTimer = (int)(MimicDuration.GetInt() - (Utils.TimeStamp - LastMimic)); } - catch { MimicDurTimer = 0; } + try + { + MimicDurTimer = (int)(MimicDuration.GetInt() - (Utils.TimeStamp - LastMimic)); + } + catch + { + MimicDurTimer = 0; + } + if (MimicDurTimer > 180) MimicDurTimer = 0; } + if ((MimicDurTimer <= 0 || !GameStates.IsInTask) && isShifted) { try @@ -225,6 +236,7 @@ public class Glitch : RoleBase { Logger.Error(ex.ToString(), "Glitch.Mimic.RpcRevertShapeshift"); } + if (!GameStates.IsInTask) { MimicDurTimer = 0; @@ -233,18 +245,36 @@ public class Glitch : RoleBase if (HackCDTimer <= 0 && KCDTimer <= 0 && MimicCDTimer <= 0 && MimicDurTimer <= 0) return; - try { HackCDTimer = (int)(HackCooldown.GetInt() - (Utils.TimeStamp - LastHack)); } - catch { HackCDTimer = 0; } + try + { + HackCDTimer = (int)(HackCooldown.GetInt() - (Utils.TimeStamp - LastHack)); + } + catch + { + HackCDTimer = 0; + } if (HackCDTimer is > 180 or < 0) HackCDTimer = 0; - try { KCDTimer = (int)(KillCooldown.GetInt() - (Utils.TimeStamp - LastKill)); } - catch { KCDTimer = 0; } + try + { + KCDTimer = (int)(KillCooldown.GetInt() - (Utils.TimeStamp - LastKill)); + } + catch + { + KCDTimer = 0; + } if (KCDTimer is > 180 or < 0) KCDTimer = 0; - try { MimicCDTimer = (int)(MimicCooldown.GetInt() + MimicDuration.GetInt() - (Utils.TimeStamp - LastMimic)); } - catch { MimicCDTimer = 0; } + try + { + MimicCDTimer = (int)(MimicCooldown.GetInt() + MimicDuration.GetInt() - (Utils.TimeStamp - LastMimic)); + } + catch + { + MimicCDTimer = 0; + } if (MimicCDTimer is > 180 or < 0) MimicCDTimer = 0; @@ -264,6 +294,7 @@ public class Glitch : RoleBase if (player.IsNonHostModClient()) SendRPCSyncTimers(); } + public static string GetHudText(PlayerControl player) { if (player == null || !player.IsAlive()) return string.Empty; @@ -290,4 +321,4 @@ public class Glitch : RoleBase MimicCDTimer = 10; SendRPCSyncTimers(); } -} +} \ No newline at end of file diff --git a/Roles/Neutral/HeadHunter.cs b/Roles/Neutral/HeadHunter.cs index c206a230b..f2d17f346 100644 --- a/Roles/Neutral/HeadHunter.cs +++ b/Roles/Neutral/HeadHunter.cs @@ -1,8 +1,8 @@ +using AmongUs.GameOptions; +using Hazel; using System; using System.Collections.Generic; using System.Linq; -using AmongUs.GameOptions; -using Hazel; using static TOHE.Options; namespace TOHE.Roles.Neutral; @@ -72,6 +72,7 @@ public class HeadHunter : RoleBase foreach (var target in Targets.ToArray()) writer.Write(target); Utils.EndRPC(writer); } + public static void ReceiveRPC(MessageReader reader) { var playerId = reader.ReadByte(); @@ -83,6 +84,12 @@ public class HeadHunter : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = KCD; + } public override void OnReportDeadBody() { @@ -102,6 +109,7 @@ public class HeadHunter : RoleBase return true; } + public static string GetHudText(PlayerControl player) { var targetId = player.PlayerId; @@ -142,4 +150,4 @@ public class HeadHunter : RoleBase SendRPC(); Utils.NotifyRoles(SpecifySeer: Utils.GetPlayerById(HeadHunterId)); } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Hookshot.cs b/Roles/Neutral/Hookshot.cs index e22633614..af4e7e310 100644 --- a/Roles/Neutral/Hookshot.cs +++ b/Roles/Neutral/Hookshot.cs @@ -48,6 +48,8 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => HookshotId != byte.MaxValue; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => true; public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); void SendRPC() diff --git a/Roles/Neutral/Jackal.cs b/Roles/Neutral/Jackal.cs index 4f35f23d0..a8d2bd15f 100644 --- a/Roles/Neutral/Jackal.cs +++ b/Roles/Neutral/Jackal.cs @@ -86,6 +86,8 @@ public class Jackal : RoleBase public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static bool CanRecruit(byte id) => id.GetAbilityUseLimit() > 0; + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool(); public override void SetButtonTexts(HudManager hud, byte id) { diff --git a/Roles/Neutral/Jester.cs b/Roles/Neutral/Jester.cs index 41bf8fa33..c9f9c629b 100644 --- a/Roles/Neutral/Jester.cs +++ b/Roles/Neutral/Jester.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AmongUs.GameOptions; +using AmongUs.GameOptions; namespace TOHE.Roles.Neutral { @@ -29,4 +24,4 @@ namespace TOHE.Roles.Neutral opt.SetVision(Options.JesterHasImpostorVision.GetBool()); } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Jinx.cs b/Roles/Neutral/Jinx.cs index 7c6d6cee9..574513658 100644 --- a/Roles/Neutral/Jinx.cs +++ b/Roles/Neutral/Jinx.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; using static TOHE.Options; namespace TOHE.Roles.Neutral; diff --git a/Roles/Neutral/Lawyer.cs b/Roles/Neutral/Lawyer.cs index 80f80d8b0..4dfd20541 100644 --- a/Roles/Neutral/Lawyer.cs +++ b/Roles/Neutral/Lawyer.cs @@ -1,8 +1,8 @@ +using HarmonyLib; +using Hazel; using System; using System.Collections.Generic; using System.Linq; -using HarmonyLib; -using Hazel; using static TOHE.Options; namespace TOHE.Roles.Neutral; diff --git a/Roles/Neutral/Magician.cs b/Roles/Neutral/Magician.cs index 726d01ddc..581a01276 100644 --- a/Roles/Neutral/Magician.cs +++ b/Roles/Neutral/Magician.cs @@ -1,7 +1,7 @@ +using AmongUs.GameOptions; using System.Collections.Generic; using System.Linq; using System.Text; -using AmongUs.GameOptions; using TOHE.Modules; using TOHE.Roles.Crewmate; using UnityEngine; @@ -102,6 +102,8 @@ public class Magician : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => true; public override void OnMurder(PlayerControl killer, PlayerControl target) { @@ -334,17 +336,20 @@ public class Magician : RoleBase b = true; continue; } + tg.Suicide(PlayerState.DeathReason.Bombed, pc); } + Bombs.Remove(bomb.Key); pc.Notify(GetString("MagicianBombExploded")); - if (b) _ = new LateTask(() => - { - if (!GameStates.IsEnded) + if (b) + _ = new LateTask(() => { - pc.Suicide(PlayerState.DeathReason.Bombed); - } - }, 0.5f, "Magician Bomb Suicide"); + if (!GameStates.IsEnded) + { + pc.Suicide(PlayerState.DeathReason.Bombed); + } + }, 0.5f, "Magician Bomb Suicide"); } var sb = new StringBuilder(); @@ -353,6 +358,7 @@ public class Magician : RoleBase { sb.Append(string.Format(GetString("MagicianBombExlodesIn"), BombDelay.GetInt() - (TimeStamp - x) + 1)); } + pc.Notify(sb.ToString()); } } @@ -370,6 +376,7 @@ public class Magician : RoleBase Main.AllPlayerSpeed[playerIdList[0]] = originalSpeed; } } + private static void RevertSpeedChanges(bool force) { foreach (var x in TempSpeeds.Where(x => SlowPPL[x.Key] + SlownessDur.GetInt() < TimeStamp || force)) @@ -380,6 +387,7 @@ public class Magician : RoleBase GetPlayerById(x.Key).MarkDirtySettings(); } } + private static Dictionary GetSnipeTargets(PlayerControl sniper) { var targets = new Dictionary(); @@ -402,6 +410,7 @@ public class Magician : RoleBase var err = target_pos.magnitude; targets.Add(target, err); } + return targets; } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Maverick.cs b/Roles/Neutral/Maverick.cs index fd4296a15..c01dc481b 100644 --- a/Roles/Neutral/Maverick.cs +++ b/Roles/Neutral/Maverick.cs @@ -49,11 +49,7 @@ public class Maverick : RoleBase public override bool IsEnable => MaverickId != byte.MaxValue; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); - - public override bool CanUseImpostorVentButton(PlayerControl pc) - { - return CanVent.GetBool(); - } + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public override bool CanUseSabotage(PlayerControl pc) { @@ -68,4 +64,9 @@ public class Maverick : RoleBase Color color = kills >= min ? Color.green : Color.red; return Utils.ColorString(color, $"{kills}/{min}"); } + + public override void OnMurder(PlayerControl killer, PlayerControl target) + { + NumOfKills++; + } } diff --git a/Roles/Neutral/Mycologist.cs b/Roles/Neutral/Mycologist.cs index 42aa3cbc7..ccbe0839b 100644 --- a/Roles/Neutral/Mycologist.cs +++ b/Roles/Neutral/Mycologist.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; +using System.Linq; using static TOHE.Options; using static TOHE.Translator; using static TOHE.Utils; @@ -134,5 +134,7 @@ namespace TOHE.Roles.Neutral public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) => IsEnable && target != null && InfectedPlayers.Contains(target.PlayerId); public override void AfterMeetingTasks() => Mycologist_.AddAbilityCD(CD.GetInt()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => true; + public override bool CanUseSabotage(PlayerControl pc) => SpreadAction.GetValue() == 1; } } \ No newline at end of file diff --git a/Roles/Neutral/NSerialKiller.cs b/Roles/Neutral/NSerialKiller.cs index bd7843b9c..074440370 100644 --- a/Roles/Neutral/NSerialKiller.cs +++ b/Roles/Neutral/NSerialKiller.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using AmongUs.GameOptions; +using System.Collections.Generic; using static TOHE.Options; namespace TOHE.Roles.Neutral; @@ -40,4 +40,4 @@ public class NSerialKiller : RoleBase public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); -} +} \ No newline at end of file diff --git a/Roles/Neutral/Necromancer.cs b/Roles/Neutral/Necromancer.cs index 2f1dc6b3a..54eac826c 100644 --- a/Roles/Neutral/Necromancer.cs +++ b/Roles/Neutral/Necromancer.cs @@ -66,6 +66,8 @@ namespace TOHE.Roles.Neutral public override bool CanUseKillButton(PlayerControl player) => player.IsAlive(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (Deathknight.DeathknightId == byte.MaxValue) @@ -158,6 +160,8 @@ namespace TOHE.Roles.Neutral public override bool CanUseKillButton(PlayerControl player) => player.IsAlive(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (Necromancer.CanBeUndead(target) && Necromancer.PartiallyRecruitedIds.Contains(target.PlayerId)) diff --git a/Roles/Neutral/Opportunist.cs b/Roles/Neutral/Opportunist.cs index c58f75123..51dc50bdb 100644 --- a/Roles/Neutral/Opportunist.cs +++ b/Roles/Neutral/Opportunist.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TOHE.Roles.Neutral +namespace TOHE.Roles.Neutral { internal class Opportunist : RoleBase { @@ -26,4 +20,4 @@ namespace TOHE.Roles.Neutral return !Options.OppoImmuneToAttacksWhenTasksDone.GetBool() || !target.Is(CustomRoles.Opportunist) || !target.AllTasksCompleted(); } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Pelican.cs b/Roles/Neutral/Pelican.cs index 9452a3ac8..74a40b2bc 100644 --- a/Roles/Neutral/Pelican.cs +++ b/Roles/Neutral/Pelican.cs @@ -1,6 +1,7 @@ -using System; +using Hazel; +using System; using System.Collections.Generic; -using Hazel; +using TOHE.Modules; using TOHE.Roles.Crewmate; using UnityEngine; @@ -38,6 +39,12 @@ public class Pelican : RoleBase } public override bool IsEnable => playerIdList.Count > 0; + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = Pelican.KillCooldown.GetFloat(); + } private static void SyncEatenList(/*byte playerId*/) { @@ -104,7 +111,8 @@ public class Pelican : RoleBase _ => throw new NotImplementedException(), }; } - public static string GetProgressText(byte playerId) + + public override string GetProgressText(byte playerId, bool comms) { var player = Utils.GetPlayerById(playerId); if (player == null) return "Invalid"; @@ -208,4 +216,18 @@ public class Pelican : RoleBase Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: pc); } } + + public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) + { + if (CanEat(killer, target.PlayerId)) + { + EatPlayer(killer, target); + //killer.RpcGuardAndKill(killer); + killer.SetKillCooldown(); + killer.RPCPlayCustomSound("Eat"); + target.RPCPlayCustomSound("Eat"); + } + + return false; + } } \ No newline at end of file diff --git a/Roles/Neutral/Pickpocket.cs b/Roles/Neutral/Pickpocket.cs index 74b20c9f4..e357d5bfc 100644 --- a/Roles/Neutral/Pickpocket.cs +++ b/Roles/Neutral/Pickpocket.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using AmongUs.GameOptions; +using System.Collections.Generic; using static TOHE.Options; namespace TOHE.Roles.Neutral; @@ -22,7 +22,7 @@ public class Pickpocket : RoleBase CanVent = BooleanOptionItem.Create(Id + 11, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Pickpocket]); HasImpostorVision = BooleanOptionItem.Create(Id + 13, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Pickpocket]); VotesPerKill = FloatOptionItem.Create(Id + 12, "VotesPerKill", new(0.1f, 10f, 0.1f), 0.3f, TabGroup.NeutralRoles, false) - .SetParent(CustomRoleSpawnChances[CustomRoles.Pickpocket]); + .SetParent(CustomRoleSpawnChances[CustomRoles.Pickpocket]); } public override void Init() @@ -42,4 +42,5 @@ public class Pickpocket : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); -} + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); +} \ No newline at end of file diff --git a/Roles/Neutral/PlagueBearer.cs b/Roles/Neutral/PlagueBearer.cs index 06890fccd..a771aef73 100644 --- a/Roles/Neutral/PlagueBearer.cs +++ b/Roles/Neutral/PlagueBearer.cs @@ -53,6 +53,7 @@ public class PlagueBearer : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = PlagueBearerCD[id]; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public static bool IsPlagued(byte pc, byte target) => PlaguedList.TryGetValue(pc, out var x) && x.Contains(target); public static void SendRPC(PlayerControl player, PlayerControl target) @@ -123,6 +124,7 @@ public class Pestilence : RoleBase } public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = PlagueBearer.PestilenceCDOpt.GetFloat(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => PlagueBearer.PestilenceCanVent.GetBool(); public override bool OnCheckMurderAsTarget(PlayerControl killer, PlayerControl target) { diff --git a/Roles/Neutral/PlagueDoctor.cs b/Roles/Neutral/PlagueDoctor.cs index 01c90df5d..1bc084b01 100644 --- a/Roles/Neutral/PlagueDoctor.cs +++ b/Roles/Neutral/PlagueDoctor.cs @@ -1,9 +1,9 @@ -using System; +using AmongUs.GameOptions; +using Hazel; +using System; using System.Collections.Generic; using System.Linq; using System.Text; -using AmongUs.GameOptions; -using Hazel; using UnityEngine; namespace TOHE.Roles.Neutral @@ -88,6 +88,7 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = Options.DefaultKillCooldown; public override bool CanUseKillButton(PlayerControl pc) => pc.GetAbilityUseLimit() != 0; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override string GetProgressText(byte id, bool comms) { diff --git a/Roles/Neutral/Postman.cs b/Roles/Neutral/Postman.cs index 89e318541..1181ba657 100644 --- a/Roles/Neutral/Postman.cs +++ b/Roles/Neutral/Postman.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; +using AmongUs.GameOptions; +using System.Collections.Generic; using System.Text; -using AmongUs.GameOptions; using static TOHE.Options; using static TOHE.Translator; @@ -51,6 +51,8 @@ public class Postman : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseKillButton(PlayerControl pc) => !IsFinished; + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public static void CheckAndResetTargets(PlayerControl deadPc, bool isDeath = false) { @@ -144,4 +146,4 @@ public class Postman : RoleBase if (Main.PlayerStates[id].Role is not Postman { IsEnable: true } pm) return string.Empty; return !pm.IsFinished ? string.Format(GetString("PostmanTarget"), Utils.GetPlayerById(pm.Target).GetRealName()) : "✓"; } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Provocateur.cs b/Roles/Neutral/Provocateur.cs index c37b2a581..7ce51d867 100644 --- a/Roles/Neutral/Provocateur.cs +++ b/Roles/Neutral/Provocateur.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AmongUs.GameOptions; +using AmongUs.GameOptions; namespace TOHE.Roles.Neutral { @@ -63,4 +58,4 @@ namespace TOHE.Roles.Neutral return false; } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Pyromaniac.cs b/Roles/Neutral/Pyromaniac.cs index a47c5373a..b3f1096d8 100644 --- a/Roles/Neutral/Pyromaniac.cs +++ b/Roles/Neutral/Pyromaniac.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using AmongUs.GameOptions; +using System.Collections.Generic; using static TOHE.Options; namespace TOHE.Roles.Neutral; @@ -48,6 +48,7 @@ public class Pyromaniac : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { @@ -67,4 +68,4 @@ public class Pyromaniac : RoleBase Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); }); } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Ritualist.cs b/Roles/Neutral/Ritualist.cs index 836367067..18172b9fd 100644 --- a/Roles/Neutral/Ritualist.cs +++ b/Roles/Neutral/Ritualist.cs @@ -1,26 +1,16 @@ -using System.Collections.Generic; -using AmongUs.GameOptions; -using HarmonyLib; -using Hazel; -using UnityEngine; using static TOHE.Options; namespace TOHE.Roles.Neutral { public static class Ritualist { - private static readonly int Id = 13000; - public static List playerIdList = []; + private const int Id = 13000; - private static OptionItem KillCooldown; - private static OptionItem RitualMaxCount; + public static OptionItem KillCooldown; + public static OptionItem RitualMaxCount; public static OptionItem CanVent; public static OptionItem HasImpostorVision; - public static Dictionary RitualCount = []; - public static Dictionary> RitualTarget = []; - - public static void SetupCustomOption() { SetupRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Ritualist); @@ -31,101 +21,5 @@ namespace TOHE.Roles.Neutral CanVent = BooleanOptionItem.Create(Id + 12, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Ritualist]); HasImpostorVision = BooleanOptionItem.Create(Id + 13, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Ritualist]); } - public static void Init() - { - playerIdList = []; - RitualCount = []; - RitualTarget = []; - } - public static void Add(byte playerId) - { - playerIdList.Add(playerId); - RitualCount.TryAdd(playerId, RitualMaxCount.GetInt()); - RitualTarget.TryAdd(playerId, []); - var pc = Utils.GetPlayerById(playerId); - pc.AddDoubleTrigger(); - - if (!AmongUsClient.Instance.AmHost) return; - if (!Main.ResetCamPlayerList.Contains(playerId)) - Main.ResetCamPlayerList.Add(playerId); - } - - private static void SendRPC(byte playerId, byte targetId) - { - if (!IsEnable || !Utils.DoRPC) return; - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetRitualist, SendOption.Reliable); - writer.Write(playerId); - writer.Write(RitualCount[playerId]); - writer.Write(targetId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - public static void ReceiveRPC(MessageReader reader) - { - byte playerId = reader.ReadByte(); - { - if (RitualCount.ContainsKey(playerId)) - RitualCount[playerId] = reader.ReadInt32(); - else - RitualCount.Add(playerId, RitualMaxCount.GetInt()); - } - { - if (RitualCount.ContainsKey(playerId)) - RitualTarget[playerId].Add(reader.ReadByte()); - else - RitualTarget.Add(playerId, []); - } - } - public static bool IsEnable => playerIdList.Count > 0; - - public static void SetKillCooldown(byte id) - { - Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); - } - public static bool OnCheckMurder(PlayerControl killer, PlayerControl target) - { - if (RitualCount[killer.PlayerId] > 0) - { - return killer.CheckDoubleTrigger(target, () => { SetRitual(killer, target); }); - } - - return true; - } - - public static bool IsRitual(byte seer, byte target) - { - if (RitualTarget[seer].Contains(target)) - { - return true; - } - return false; - } - public static void SetRitual(PlayerControl killer, PlayerControl target) - { - if (!IsRitual(killer.PlayerId, target.PlayerId)) - { - RitualCount[killer.PlayerId]--; - RitualTarget[killer.PlayerId].Add(target.PlayerId); - Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()}:Reveal target → {target.GetNameWithRole().RemoveHtmlTags()} || Remaining: {RitualCount[killer.PlayerId]} uses", "Ritualist"); - Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target); - - SendRPC(killer.PlayerId, target.PlayerId); - //キルクールの適正化 - killer.SetKillCooldown(); - //killer.RpcGuardAndKill(target); - } - } - public static bool IsShowTargetRole(PlayerControl seer, PlayerControl target) - { - var IsWatch = false; - RitualTarget.Do(x => - { - if (x.Value != null && seer.PlayerId == x.Key && x.Value.Contains(target.PlayerId) && Utils.GetPlayerById(x.Key).IsAlive()) - IsWatch = true; - }); - return IsWatch; - } - public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); - - public static string GetRitualCount(byte playerId) => Utils.ColorString(RitualCount[playerId] > 0 ? Utils.GetRoleColor(CustomRoles.Ritualist).ShadeColor(0.25f) : Color.gray, RitualCount.TryGetValue(playerId, out var shotLimit) ? $"({shotLimit})" : "Invalid"); } } \ No newline at end of file diff --git a/Roles/Neutral/Romantic.cs b/Roles/Neutral/Romantic.cs index e1c23e2eb..9cdc3a700 100644 --- a/Roles/Neutral/Romantic.cs +++ b/Roles/Neutral/Romantic.cs @@ -1,6 +1,6 @@ +using Hazel; using System; using System.Collections.Generic; -using Hazel; using TOHE.Modules; using UnityEngine; using static TOHE.Options; @@ -77,6 +77,7 @@ public class Romantic : RoleBase writer.Write(PartnerId); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { PartnerId = reader.ReadByte(); @@ -92,6 +93,7 @@ public class Romantic : RoleBase if (Math.Abs(beforeCD - Main.AllPlayerKillCooldown[RomanticId]) > 0.5f) Romantic_?.SyncSettings(); } + public static bool KnowRole(PlayerControl player, PlayerControl target) { if (!KnowTargetRole.GetBool()) return false; @@ -146,6 +148,7 @@ public class Romantic : RoleBase return false; } + public static string TargetMark(PlayerControl seer, PlayerControl target) { if (!seer.Is(CustomRoles.Romantic)) @@ -161,11 +164,13 @@ public class Romantic : RoleBase ? Utils.ColorString(Utils.GetRoleColor(CustomRoles.Romantic), "♥") : string.Empty; } + public static string GetTargetText(byte playerId) => playerId != RomanticId ? null : Utils.ColorString(!HasPickedPartner ? Color.white : Utils.GetRoleColor(CustomRoles.Romantic), $"{(!HasPickedPartner ? "PICK PARTNER" : "♥")}"); public override void OnReportDeadBody() => IsPartnerProtected = false; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public static void ChangeRole() { @@ -254,6 +259,12 @@ public class VengefulRomantic : RoleBase public override bool IsEnable => VengefulRomanticId != byte.MaxValue; public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead && !HasKilledKiller; + public override bool CanUseImpostorVentButton(PlayerControl pc) => Romantic.VengefulCanVent.GetBool(); + + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = Romantic.VengefulKCD.GetFloat(); + } public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { @@ -269,11 +280,13 @@ public class VengefulRomantic : RoleBase killer.Suicide(PlayerState.DeathReason.Misfire); return false; } + public static string GetTargetText(byte playerId) { var player = Utils.GetPlayerById(playerId); return player == null ? null : Utils.ColorString(HasKilledKiller ? Color.green : Utils.GetRoleColor(CustomRoles.VengefulRomantic), $"{(HasKilledKiller ? "✓" : "☹️")}"); } + public static void SendRPC() { if (!Utils.DoRPC) return; @@ -281,6 +294,7 @@ public class VengefulRomantic : RoleBase writer.Write(Target); AmongUsClient.Instance.FinishRpcImmediately(writer); } + public static void ReceiveRPC(MessageReader reader) { byte target = reader.ReadByte(); @@ -307,4 +321,10 @@ public class RuthlessRomantic : RoleBase } public override bool IsEnable => playerIdList.Count > 0; -} + public override bool CanUseImpostorVentButton(PlayerControl pc) => Romantic.RuthlessCanVent.GetBool(); + + public override void SetKillCooldown(byte id) + { + Main.AllPlayerKillCooldown[id] = Romantic.RuthlessKCD.GetFloat(); + } +} \ No newline at end of file diff --git a/Roles/Neutral/Sidekick.cs b/Roles/Neutral/Sidekick.cs index b98476f2d..2ee354cde 100644 --- a/Roles/Neutral/Sidekick.cs +++ b/Roles/Neutral/Sidekick.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using AmongUs.GameOptions; +using System.Collections.Generic; namespace TOHE.Roles.Neutral; @@ -22,7 +22,9 @@ public class Sidekick : RoleBase } public override bool IsEnable => playerIdList.Count > 0; + public override bool CanUseImpostorVentButton(PlayerControl pc) => Jackal.CanVent.GetBool(); public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = Jackal.KillCooldownSK.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(Jackal.HasImpostorVision.GetBool()); public override void SetButtonTexts(HudManager __instance, byte id) => __instance.SabotageButton.ToggleVisible(Jackal.CanSabotageSK.GetBool()); -} + public override bool CanUseSabotage(PlayerControl pc) => Jackal.CanSabotageSK.GetBool(); +} \ No newline at end of file diff --git a/Roles/Neutral/SoulHunter.cs b/Roles/Neutral/SoulHunter.cs index 77f5253e3..ace8f4eda 100644 --- a/Roles/Neutral/SoulHunter.cs +++ b/Roles/Neutral/SoulHunter.cs @@ -1,7 +1,7 @@ -using System; -using System.Linq; -using AmongUs.GameOptions; +using AmongUs.GameOptions; using Hazel; +using System; +using System.Linq; using static TOHE.Options; using static TOHE.Translator; using static TOHE.Utils; @@ -72,6 +72,7 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => SoulHunterId != byte.MaxValue; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = WaitingTimeAfterMeeting.GetFloat() + 1.5f; public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public static bool IsSoulHunterTarget(byte id) => Main.PlayerStates.Any(x => x.Value.Role is SoulHunter { IsEnable: true } sh && sh.IsTargetBlocked && sh.CurrentTarget.ID == id); public static SoulHunter GetSoulHunter(byte targetId) => Main.PlayerStates.FirstOrDefault(x => x.Value.Role is SoulHunter { IsEnable: true } sh && sh.IsTargetBlocked && sh.CurrentTarget.ID == targetId).Value.Role as SoulHunter; @@ -85,6 +86,7 @@ namespace TOHE.Roles.Neutral writer.Write(CurrentTarget.FROZEN); EndRPC(writer); } + public static void ReceiveRPC(MessageReader reader) { byte id = reader.ReadByte(); @@ -244,4 +246,4 @@ namespace TOHE.Roles.Neutral return $"<#777777>- <#{(sh.Souls >= souldsNeeded ? "00ff00" : "ffffff")}>{sh.Souls}/{souldsNeeded}"; } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Spiritcaller.cs b/Roles/Neutral/Spiritcaller.cs index af4b77ff4..464ef1b6f 100644 --- a/Roles/Neutral/Spiritcaller.cs +++ b/Roles/Neutral/Spiritcaller.cs @@ -65,6 +65,7 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public static bool InProtect(PlayerControl player) => player.Is(CustomRoles.Spiritcaller) && ProtectTimeStamp > Utils.TimeStamp; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) diff --git a/Roles/Neutral/Sprayer.cs b/Roles/Neutral/Sprayer.cs index fcd129ed1..070ead6fb 100644 --- a/Roles/Neutral/Sprayer.cs +++ b/Roles/Neutral/Sprayer.cs @@ -1,6 +1,6 @@ -using System; +using AmongUs.GameOptions; +using System; using System.Collections.Generic; -using AmongUs.GameOptions; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -84,6 +84,8 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => SprayerId != byte.MaxValue; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => true; public override void OnSabotage(PlayerControl pc) { diff --git a/Roles/Neutral/Succubus.cs b/Roles/Neutral/Succubus.cs index adbd8a295..2f1cd834a 100644 --- a/Roles/Neutral/Succubus.cs +++ b/Roles/Neutral/Succubus.cs @@ -70,6 +70,7 @@ public class Succubus : RoleBase public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = id.GetAbilityUseLimit() >= 1 ? CharmCooldown.GetFloat() + (CharmMax.GetInt() - id.GetAbilityUseLimit()) * CharmCooldownIncrese.GetFloat() : 300f; public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead && player.GetAbilityUseLimit() >= 1; + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { diff --git a/Roles/Neutral/Sunnyboy.cs b/Roles/Neutral/Sunnyboy.cs index b83b9a27e..f74f60515 100644 --- a/Roles/Neutral/Sunnyboy.cs +++ b/Roles/Neutral/Sunnyboy.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using AmongUs.GameOptions; +using AmongUs.GameOptions; namespace TOHE.Roles.Neutral { @@ -28,4 +23,4 @@ namespace TOHE.Roles.Neutral AURoleOptions.ScientistBatteryCharge = 60f; } } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Totocalcio.cs b/Roles/Neutral/Totocalcio.cs index cc1b265ba..a7b5a87ea 100644 --- a/Roles/Neutral/Totocalcio.cs +++ b/Roles/Neutral/Totocalcio.cs @@ -1,7 +1,7 @@ -using System.Collections.Generic; -using System.Linq; using Hazel; using Il2CppSystem; +using System.Collections.Generic; +using System.Linq; using TOHE.Modules; using UnityEngine; using static TOHE.Options; @@ -79,6 +79,7 @@ public class Totocalcio : RoleBase } public override bool CanUseKillButton(PlayerControl player) => !player.Data.IsDead && (BetTimes >= 1); + public override bool CanUseImpostorVentButton(PlayerControl pc) => false; public override void SetKillCooldown(byte id) { @@ -140,7 +141,8 @@ public class Totocalcio : RoleBase return tc.BetPlayer == target.PlayerId ? Utils.ColorString(Utils.GetRoleColor(CustomRoles.Totocalcio), "♦") : string.Empty; } } - public static string GetProgressText(byte playerId) + + public override string GetProgressText(byte playerId, bool comms) { var player = Utils.GetPlayerById(playerId); if (Main.PlayerStates[playerId].Role is not Totocalcio tc) return string.Empty; diff --git a/Roles/Neutral/Traitor.cs b/Roles/Neutral/Traitor.cs index 318835820..8d60360ed 100644 --- a/Roles/Neutral/Traitor.cs +++ b/Roles/Neutral/Traitor.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using AmongUs.GameOptions; +using System.Collections.Generic; using static TOHE.Options; namespace TOHE.Roles.Neutral; @@ -42,5 +42,6 @@ public class Traitor : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public override bool CanUseSabotage(PlayerControl pc) => CanSabotage.GetBool(); -} +} \ No newline at end of file diff --git a/Roles/Neutral/Vengeance.cs b/Roles/Neutral/Vengeance.cs index 6979c540d..76be6ac0e 100644 --- a/Roles/Neutral/Vengeance.cs +++ b/Roles/Neutral/Vengeance.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using AmongUs.GameOptions; +using System.Collections.Generic; using static TOHE.Options; using static TOHE.Translator; @@ -54,6 +54,7 @@ public class Vengeance : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); public override bool OnCheckMurderAsTarget(PlayerControl killer, PlayerControl target) { @@ -84,7 +85,12 @@ public class Vengeance : RoleBase return; } - if ((seconds <= 0 || GameStates.IsMeeting) && player.IsAlive()) { player.Kill(player); return; } + if ((seconds <= 0 || GameStates.IsMeeting) && player.IsAlive()) + { + player.Kill(player); + return; + } + player.Notify(string.Format(GetString("VengeanceRevenge"), seconds), 1.1f); Timer = seconds; @@ -109,4 +115,4 @@ public class Vengeance : RoleBase killer.Kill(killer); return false; } -} +} \ No newline at end of file diff --git a/Roles/Neutral/Virus.cs b/Roles/Neutral/Virus.cs index f8522a880..4d12b1cba 100644 --- a/Roles/Neutral/Virus.cs +++ b/Roles/Neutral/Virus.cs @@ -60,6 +60,7 @@ namespace TOHE.Roles.Neutral public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); private static void SendRPCInfectKill(byte virusId, byte target = 255) { diff --git a/Roles/Neutral/Vulture.cs b/Roles/Neutral/Vulture.cs index 7a224a128..49e61995b 100644 --- a/Roles/Neutral/Vulture.cs +++ b/Roles/Neutral/Vulture.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -171,7 +171,17 @@ public class Vulture : RoleBase { if (!seer.Is(CustomRoles.Vulture)) return string.Empty; if (target != null && seer.PlayerId != target.PlayerId) return string.Empty; - if (GameStates.IsMeeting) return string.Empty; - return Utils.ColorString(Color.white, LocateArrow.GetArrows(seer)); + return GameStates.IsMeeting ? string.Empty : Utils.ColorString(Color.white, LocateArrow.GetArrows(seer)); + } + + public override void OnFixedUpdate(PlayerControl pc) + { + var playerId = pc.PlayerId; + if (BodyReportCount[playerId] >= NumberOfReportsToWin.GetInt() && GameStates.IsInTask) + { + BodyReportCount[playerId] = NumberOfReportsToWin.GetInt(); + CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Vulture); + CustomWinnerHolder.WinnerIds.Add(playerId); + } } } \ No newline at end of file diff --git a/Roles/Neutral/WeaponMaster.cs b/Roles/Neutral/WeaponMaster.cs index 279731b64..166bfa9ce 100644 --- a/Roles/Neutral/WeaponMaster.cs +++ b/Roles/Neutral/WeaponMaster.cs @@ -1,6 +1,6 @@ -using System.Collections.Generic; using AmongUs.GameOptions; using Hazel; +using System.Collections.Generic; using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -81,6 +81,8 @@ public class WeaponMaster : RoleBase } public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanVent.GetBool(); + public override bool CanUseSabotage(PlayerControl pc) => true; public override void ApplyGameOptions(IGameOptions opt, byte id) { @@ -183,14 +185,18 @@ public class WeaponMaster : RoleBase { if (Mode == 2) { - _ = new LateTask(() => { pc?.MyPhysics?.RpcBootFromVent(vent.Id); }, 0.5f); + pc?.MyPhysics?.RpcBootFromVent(vent.Id); } } + public override string GetProgressText(byte playerId, bool comms) + { + return !playerId.IsPlayerModClient() ? GetHudAndProgressText(playerId) : string.Empty; + } + public static string GetHudAndProgressText(byte id) { - if (Main.PlayerStates[id].Role is not WeaponMaster { IsEnable: true } wm) return string.Empty; - return string.Format(GetString("WMMode"), ModeToText(wm.Mode)); + return Main.PlayerStates[id].Role is not WeaponMaster { IsEnable: true } wm ? string.Empty : string.Format(GetString("WMMode"), ModeToText(wm.Mode)); } public static string ModeToText(byte mode) { diff --git a/Roles/Neutral/Werewolf.cs b/Roles/Neutral/Werewolf.cs index cc82e1447..34ad388fa 100644 --- a/Roles/Neutral/Werewolf.cs +++ b/Roles/Neutral/Werewolf.cs @@ -57,6 +57,8 @@ public class Werewolf : RoleBase public override bool IsEnable => playerIdList.Count > 0; public override void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public override void ApplyGameOptions(IGameOptions opt, byte id) => opt.SetVision(HasImpostorVision.GetBool()); + public override bool CanUseImpostorVentButton(PlayerControl pc) => CanRampage || IsRampaging || pc.inVent; + public override bool CanUseKillButton(PlayerControl pc) => IsRampaging; void SendRPC() { diff --git a/Roles/RoleBase.cs b/Roles/RoleBase.cs index 958b882c5..25f663464 100644 --- a/Roles/RoleBase.cs +++ b/Roles/RoleBase.cs @@ -66,6 +66,22 @@ namespace TOHE public virtual void OnPet(PlayerControl pc) { + int x = IRandom.Instance.Next(1, 16); + string suffix; + if (x >= 14) + { + x -= 13; + suffix = pc.GetCustomRole().GetCustomRoleTypes() switch + { + CustomRoleTypes.Impostor => $"Imp{x}", + CustomRoleTypes.Neutral => $"Neutral{x}", + CustomRoleTypes.Crewmate => x == 1 ? "Crew" : pc.GetTaskState().hasTasks && pc.GetTaskState().IsTaskFinished ? "CrewTaskDone" : "CrewWithTasksLeft", + _ => x.ToString(), + }; + } + else suffix = x.ToString(); + + pc.Notify(Translator.GetString($"NoPetActionMsg{suffix}")); } public virtual void OnSabotage(PlayerControl pc) @@ -97,6 +113,7 @@ namespace TOHE public virtual bool CheckReportDeadBody(PlayerControl reporter, GameData.PlayerInfo target, PlayerControl killer) { + return true; } public virtual void AfterMeetingTasks() diff --git a/main.cs b/main.cs index e8187b221..4ff38c096 100644 --- a/main.cs +++ b/main.cs @@ -1,7 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; using AmongUs.GameOptions; using BepInEx; using BepInEx.Configuration; @@ -9,6 +5,10 @@ using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using HarmonyLib; using Il2CppInterop.Runtime.Injection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using TOHE; using TOHE.Roles.Neutral; using UnityEngine;