From 01fc67037f9ae7630c7be9ab3532773b48d1538b Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Thu, 2 Nov 2023 19:13:43 +0100 Subject: [PATCH] Fix more bugs, Add some settings, No SS animations --- GameMode/FFAManager.cs | 3 +- Modules/DebugModeManager.cs | 7 +- Modules/DisableDevice.cs | 2 +- Modules/ExtendedPlayerControl.cs | 3 + .../GameOptionsSender/GameOptionsSender.cs | 15 +- Modules/GuessManager.cs | 2 +- Modules/OptionHolder.cs | 82 +++++++-- Modules/OptionShower.cs | 2 +- Modules/Utils.cs | 39 ++-- Patches/ChatCommandPatch.cs | 3 +- Patches/ChatControlPatch.cs | 2 +- Patches/CheckGameEndPatch.cs | 10 +- Patches/HudPatch.cs | 1 + Patches/HudSpritePatch.cs | 1 + Patches/MeetingHudPatch.cs | 119 +++++++------ Patches/OutroPatch.cs | 8 +- Patches/PetActionsPatch.cs | 12 +- Patches/PlayerContorolPatch.cs | 166 ++++++++++-------- Patches/PlayerJoinAndLeftPatch.cs | 2 +- Patches/SabotageSystemPatch.cs | 104 +++++++++-- Patches/ShipStatusPatch.cs | 6 +- Patches/onGameStartedPatch.cs | 1 + Resources/Config/EACList.txt | 1 + Resources/String.csv | 39 ++-- Roles/Crewmate/Addict.cs | 4 +- Roles/Crewmate/Aid.cs | 4 +- Roles/Crewmate/Bloodhound.cs | 2 +- Roles/Crewmate/CameraMan.cs | 32 +--- Roles/Crewmate/Chameleon.cs | 2 +- Roles/Crewmate/Doormaster.cs | 2 +- Roles/Crewmate/Jailer.cs | 4 +- Roles/Crewmate/Mediumshiper.cs | 2 +- Roles/Crewmate/Merchant.cs | 2 +- Roles/Crewmate/NiceSwapper.cs | 2 +- Roles/Crewmate/ParityCop.cs | 2 +- Roles/Crewmate/Ricochet.cs | 2 +- Roles/Crewmate/Spy.cs | 2 +- Roles/Crewmate/Tether.cs | 2 +- Roles/Impostor/Assassin.cs | 2 +- Roles/Impostor/Camouflager.cs | 2 +- Roles/Impostor/Dazzler.cs | 2 +- Roles/Impostor/Devourer.cs | 2 +- Roles/Impostor/Disperser.cs | 2 +- Roles/Impostor/Hacker.cs | 2 +- Roles/Impostor/Hitman.cs | 2 +- Roles/Impostor/Lurker.cs | 2 +- Roles/Impostor/RiftMaker.cs | 2 +- Roles/Impostor/Sapper.cs | 2 +- Roles/Impostor/Swooper.cs | 2 +- Roles/Impostor/Undertaker.cs | 2 +- Roles/Neutral/Agitater.cs | 2 +- Roles/Neutral/CursedSoul.cs | 2 + TOHE.csproj | 2 +- main.cs | 1 + 54 files changed, 461 insertions(+), 264 deletions(-) diff --git a/GameMode/FFAManager.cs b/GameMode/FFAManager.cs index a1145dd73..4c5619741 100644 --- a/GameMode/FFAManager.cs +++ b/GameMode/FFAManager.cs @@ -205,6 +205,7 @@ internal static class FFAManager { bool sync = false; bool mark = false; + var nowKCD = Main.AllPlayerKillCooldown[killer.PlayerId]; byte EffectType; if (Main.NormalOptions.MapId != 4) EffectType = (byte)HashRandom.Next(0, 10); else EffectType = (byte)HashRandom.Next(4, 10); @@ -292,7 +293,7 @@ internal static class FFAManager Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat(); } - if (sync) + if (sync || nowKCD != Main.AllPlayerKillCooldown[killer.PlayerId]) { mark = false; killer.SyncSettings(); diff --git a/Modules/DebugModeManager.cs b/Modules/DebugModeManager.cs index 0b4e9020a..d75278ad0 100644 --- a/Modules/DebugModeManager.cs +++ b/Modules/DebugModeManager.cs @@ -6,7 +6,12 @@ public static class DebugModeManager { // これが有効の時、通常のゲームに支障のないデバッグ機能(詳細ログ・ゲーム外でのデバッグ表示など)が有効化される。 // また、ゲーム内オプションでデバッグモードを有効化することができる。 - public static bool AmDebugger { get; private set; } + public static bool AmDebugger { get; private set; } = +#if DEBUG + true; +#else + false; +#endif // これが有効の時、通常のゲームを破壊する可能性のある強力なデバッグ機能(テレポートなど)が有効化される。 public static bool IsDebugMode => AmDebugger && EnableDebugMode != null && EnableDebugMode.GetBool(); diff --git a/Modules/DisableDevice.cs b/Modules/DisableDevice.cs index 64a30c2e0..8f217e7bd 100644 --- a/Modules/DisableDevice.cs +++ b/Modules/DisableDevice.cs @@ -119,7 +119,7 @@ class DisableDevice DesyncComms.Remove(pc.PlayerId); pc.RpcDesyncRepairSystem(SystemTypes.Comms, 16); - if (Main.NormalOptions.MapId == 1) + if (Main.NormalOptions.MapId is 1 or 5) // Mira HQ or The Fungle pc.RpcDesyncRepairSystem(SystemTypes.Comms, 17); } } diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index 51ced20d9..182c1517c 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -895,6 +895,9 @@ static class ExtendedPlayerControl case CustomRoles.RiftMaker: Main.AllPlayerKillCooldown[player.PlayerId] = RiftMaker.KillCooldown.GetFloat(); break; + case CustomRoles.Puppeteer: + Main.AllPlayerKillCooldown[player.PlayerId] = Options.PuppeteerKCD.GetFloat(); + break; case CustomRoles.Saboteur: Main.AllPlayerKillCooldown[player.PlayerId] = Options.SaboteurCDAfterMeetings.GetFloat(); break; diff --git a/Modules/GameOptionsSender/GameOptionsSender.cs b/Modules/GameOptionsSender/GameOptionsSender.cs index 959409b57..8f2d39895 100644 --- a/Modules/GameOptionsSender/GameOptionsSender.cs +++ b/Modules/GameOptionsSender/GameOptionsSender.cs @@ -61,20 +61,13 @@ public abstract class GameOptionsSender } public virtual void SendOptionsArray(Il2CppStructArray optionArray) { - try + for (byte i = 0; i < GameManager.Instance.LogicComponents.Count; i++) { - for (byte i = 0; i < GameManager.Instance?.LogicComponents?.Count; i++) + if (GameManager.Instance.LogicComponents[(Index)i].TryCast(out _)) { - if (GameManager.Instance.LogicComponents[(Index)i].TryCast(out _)) - { - SendOptionsArray(optionArray, i, -1); - } + SendOptionsArray(optionArray, i, -1); } } - catch (Exception ex) - { - Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray-1"); - } } protected virtual void SendOptionsArray(Il2CppStructArray optionArray, byte LogicOptionsIndex, int targetClientId) { @@ -104,7 +97,7 @@ public abstract class GameOptionsSender } catch (Exception ex) { - Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray-2"); + Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray"); } } public abstract IGameOptions BuildGameOptions(); diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index c395ef483..aad0e2058 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -783,7 +783,7 @@ public static class GuessManager // msg += rd.Next(1, 100) < 50 ? string.Empty : " "; // msg += Utils.GetRoleName(role); //} - msg = "."; + msg = Utils.EmptyMessage(); var player = x[rd.Next(0, totalAlive)]; DestroyableSingleton.Instance.Chat.AddChat(player, msg); var writer = CustomRpcSender.Create("MessagesToSend", SendOption.None); diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 30dbca8c5..af9f7d9b3 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -126,6 +126,7 @@ public static class Options //public static OptionItem ShareLobbyMinPlayer; public static OptionItem DisableShieldAnimations; public static OptionItem DisableCrackedGlass; + public static OptionItem DisableShapeshiftAnimations; public static OptionItem DisableKillAnimationOnGuess; public static OptionItem DisableVanillaRoles; public static OptionItem DisableHiddenRoles; @@ -200,6 +201,9 @@ public static class Options public static OptionItem GGTryHideMsg; public static OptionItem LuckeyProbability; public static OptionItem LuckyProbability; + public static OptionItem PuppeteerDelay; + public static OptionItem PuppeteerKCD; + public static OptionItem PuppeteerCD; public static OptionItem VindicatorAdditionalVote; public static OptionItem VindicatorHideVote; public static OptionItem MayorAdditionalVote; @@ -598,17 +602,24 @@ public static class Options public static OptionItem AirshipAdditionalSpawn; public static OptionItem AirshipVariableElectrical; public static OptionItem DisableAirshipMovingPlatform; + public static OptionItem DisableSporeTriggerOnFungle; + public static OptionItem DisableZiplineOnFungle; + public static OptionItem DisableZiplineFromTop; + public static OptionItem DisableZiplineFromUnder; // Sabotage public static OptionItem CommsCamouflage; public static OptionItem CommsCamouflageDisableOnFungle; public static OptionItem DisableReportWhenCC; public static OptionItem SabotageTimeControl; + public static OptionItem SkeldReactorTimeLimit; + public static OptionItem SkeldO2TimeLimit; + public static OptionItem MiraReactorTimeLimit; + public static OptionItem MiraO2TimeLimit; public static OptionItem PolusReactorTimeLimit; public static OptionItem AirshipReactorTimeLimit; - public static OptionItem MiraO2TimeLimit; - public static OptionItem MushroomMixupTime; - public static OptionItem MiraReactorTimeLimit; + public static OptionItem FungleReactorTimeLimit; + public static OptionItem FungleMushroomMixupDuration; public static OptionItem LightsOutSpecialSettings; public static OptionItem DisableAirshipViewingDeckLightsPanel; public static OptionItem DisableAirshipGapRoomLightsPanel; @@ -1234,6 +1245,15 @@ public static class Options RoleLoadingText = "Impostor roles\nPuppeteer"; SetupRoleOptions(3900, TabGroup.ImpostorRoles, CustomRoles.Puppeteer); + PuppeteerCD = FloatOptionItem.Create(3911, "PuppeteerCD", new(2.5f, 60f, 2.5f), 22.5f, TabGroup.ImpostorRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Puppeteer]) + .SetValueFormat(OptionFormat.Seconds); + PuppeteerKCD = FloatOptionItem.Create(3912, "PuppeteerKCD", new(2.5f, 60f, 2.5f), 25f, TabGroup.ImpostorRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Puppeteer]) + .SetValueFormat(OptionFormat.Seconds); + PuppeteerDelay = IntegerOptionItem.Create(3910, "PuppeteerDelay", new(0, 20, 1), 5, TabGroup.ImpostorRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Puppeteer]) + .SetValueFormat(OptionFormat.Seconds); RoleLoadingText = "Impostor roles\nScavenger"; SetupRoleOptions(4000, TabGroup.ImpostorRoles, CustomRoles.Scavenger); ScavengerKillCooldown = FloatOptionItem.Create(4010, "KillCooldown", new(5f, 180f, 2.5f), 40f, TabGroup.ImpostorRoles, false) @@ -2621,10 +2641,26 @@ public static class Options AirshipVariableElectrical = BooleanOptionItem.Create(22100, "AirshipVariableElectrical", false, TabGroup.GameSettings, false) .SetGameMode(CustomGameMode.Standard) .SetColor(new Color32(19, 188, 233, byte.MaxValue)); - //Disable Airship Moving Platform + // Disable Airship Moving Platform DisableAirshipMovingPlatform = BooleanOptionItem.Create(22110, "DisableAirshipMovingPlatform", false, TabGroup.GameSettings, false) .SetColor(new Color32(19, 188, 233, byte.MaxValue)); + // Disable Spore Triggers on Fungle + DisableSporeTriggerOnFungle = BooleanOptionItem.Create(22130, "DisableSporeTriggerOnFungle", false, TabGroup.GameSettings, false) + .SetColor(new Color32(19, 188, 233, byte.MaxValue)); + + // Disable Zipline On Fungle + DisableZiplineOnFungle = BooleanOptionItem.Create(22305, "DisableZiplineOnFungle", false, TabGroup.GameSettings, false) + .SetColor(new Color32(19, 188, 233, byte.MaxValue)); + // Disable Zipline From Top + DisableZiplineFromTop = BooleanOptionItem.Create(22308, "DisableZiplineFromTop", false, TabGroup.GameSettings, false) + .SetParent(DisableZiplineOnFungle) + .SetColor(new Color32(19, 188, 233, byte.MaxValue)); + // Disable Zipline From Under + DisableZiplineFromUnder = BooleanOptionItem.Create(22310, "DisableZiplineFromUnder", false, TabGroup.GameSettings, false) + .SetParent(DisableZiplineOnFungle) + .SetColor(new Color32(19, 188, 233, byte.MaxValue)); + // Reset Doors After Meeting ResetDoorsEveryTurns = BooleanOptionItem.Create(22120, "ResetDoorsEveryTurns", false, TabGroup.GameSettings, false) .SetGameMode(CustomGameMode.Standard) @@ -2673,30 +2709,46 @@ public static class Options .SetColor(new Color32(243, 96, 96, byte.MaxValue)) .SetGameMode(CustomGameMode.Standard); - PolusReactorTimeLimit = FloatOptionItem.Create(22412, "PolusReactorTimeLimit", new(1f, 60f, 1f), 40f, TabGroup.GameSettings, false) + // The Skeld + SkeldReactorTimeLimit = FloatOptionItem.Create(22418, "SkeldReactorTimeLimit", new(5f, 90f, 1f), 30f, TabGroup.GameSettings, false) .SetParent(SabotageTimeControl) .SetValueFormat(OptionFormat.Seconds) .SetGameMode(CustomGameMode.Standard); - AirshipReactorTimeLimit = FloatOptionItem.Create(22414, "AirshipReactorTimeLimit", new(1f, 90f, 1f), 60f, TabGroup.GameSettings, false) + SkeldO2TimeLimit = FloatOptionItem.Create(22419, "SkeldO2TimeLimit", new(5f, 90f, 1f), 30f, TabGroup.GameSettings, false) .SetParent(SabotageTimeControl) .SetValueFormat(OptionFormat.Seconds) .SetGameMode(CustomGameMode.Standard); - MiraO2TimeLimit = FloatOptionItem.Create(22416, "MiraO2TimeLimit", new(1f, 60f, 1f), 35f, TabGroup.GameSettings, false) + // Mira HQ + MiraReactorTimeLimit = FloatOptionItem.Create(22422, "MiraReactorTimeLimit", new(5f, 90f, 1f), 45f, TabGroup.GameSettings, false) .SetParent(SabotageTimeControl) .SetValueFormat(OptionFormat.Seconds) .SetGameMode(CustomGameMode.Standard); - MiraReactorTimeLimit = FloatOptionItem.Create(22420, "MiraReactorTimeLimit", new(1f, 60f, 1f), 35f, TabGroup.GameSettings, false) + MiraO2TimeLimit = FloatOptionItem.Create(22423, "MiraO2TimeLimit", new(5f, 90f, 1f), 45f, TabGroup.GameSettings, false) + .SetParent(SabotageTimeControl) + .SetValueFormat(OptionFormat.Seconds) + .SetGameMode(CustomGameMode.Standard); + // Polus + PolusReactorTimeLimit = FloatOptionItem.Create(22424, "PolusReactorTimeLimit", new(5f, 90f, 1f), 60f, TabGroup.GameSettings, false) + .SetParent(SabotageTimeControl) + .SetValueFormat(OptionFormat.Seconds) + .SetGameMode(CustomGameMode.Standard); + // The Airship + AirshipReactorTimeLimit = FloatOptionItem.Create(22425, "AirshipReactorTimeLimit", new(5f, 90f, 1f), 90f, TabGroup.GameSettings, false) + .SetParent(SabotageTimeControl) + .SetValueFormat(OptionFormat.Seconds) + .SetGameMode(CustomGameMode.Standard); + // The Fungle + FungleReactorTimeLimit = FloatOptionItem.Create(22426, "FungleReactorTimeLimit", new(5f, 90f, 1f), 60f, TabGroup.GameSettings, false) + .SetParent(SabotageTimeControl) + .SetValueFormat(OptionFormat.Seconds) + .SetGameMode(CustomGameMode.Standard); + FungleMushroomMixupDuration = FloatOptionItem.Create(22427, "FungleMushroomMixupDuration", new(5f, 90f, 1f), 10f, TabGroup.GameSettings, false) .SetParent(SabotageTimeControl) .SetValueFormat(OptionFormat.Seconds) .SetGameMode(CustomGameMode.Standard); - //MushroomMixupTime = FloatOptionItem.Create(22418, "MushroomMixupTime", new(1f, 15f, 1f), 7f, TabGroup.GameSettings, false) - // .SetParent(SabotageTimeControl) - // .SetValueFormat(OptionFormat.Seconds) - // .SetGameMode(CustomGameMode.Standard); LoadingPercentage = 72; - // LightsOutSpecialSettings LightsOutSpecialSettings = BooleanOptionItem.Create(22500, "LightsOutSpecialSettings", false, TabGroup.GameSettings, false) .SetColor(new Color32(243, 96, 96, byte.MaxValue)) @@ -2727,6 +2779,10 @@ public static class Options .SetGameMode(CustomGameMode.Standard) .SetColor(new Color32(255, 153, 153, byte.MaxValue)); DisableCrackedGlass = BooleanOptionItem.Create(22603, "DisableCrackedGlass", false, TabGroup.GameSettings, false) + .SetGameMode(CustomGameMode.Standard) + .SetHidden(true) + .SetColor(new Color32(255, 153, 153, byte.MaxValue)); + DisableShapeshiftAnimations = BooleanOptionItem.Create(22604, "DisableShapeshiftAnimations", false, TabGroup.GameSettings, false) .SetGameMode(CustomGameMode.Standard) .SetColor(new Color32(255, 153, 153, byte.MaxValue)); DisableVanillaRoles = BooleanOptionItem.Create(22600, "DisableVanillaRoles", true, TabGroup.GameSettings, false) diff --git a/Modules/OptionShower.cs b/Modules/OptionShower.cs index 265c588a4..3085f8278 100644 --- a/Modules/OptionShower.cs +++ b/Modules/OptionShower.cs @@ -64,7 +64,7 @@ public static class OptionShower string ruleFooter = Utils.ColorString(Palette.ImpostorRed.ShadeColor(-0.5f), "┗ "); } - foreach (var opt in OptionItem.AllOptions.Where(x => x.Id >= 90000 && !x.IsHiddenOn(Options.CurrentGameMode) && x.Parent == null && !x.IsText)) + foreach (var opt in OptionItem.AllOptions.Where(x => (x.Id >= 90000 || (x.Id >= 600000 && x.Id <= 700000)) && !x.IsHiddenOn(Options.CurrentGameMode) && x.Parent == null && !x.IsText)) { if (opt.IsHeader) sb.Append('\n'); sb.Append($"{opt.GetName()}: {opt.GetString()}\n"); diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 1d99674aa..f878cb9e2 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -2,6 +2,7 @@ using AmongUs.Data; using AmongUs.GameOptions; using Hazel; using Il2CppInterop.Runtime.InteropTypes; +using Il2CppSystem.Runtime.Remoting.Messaging; using InnerNet; using System; using System.Collections.Generic; @@ -458,11 +459,10 @@ public static class Utils return (RoleText, RoleColor); } - public static string GetKillCountText(byte playerId) + public static string GetKillCountText(byte playerId, bool ffa = false) { - int count = Main.PlayerStates.Count(x => x.Value.GetRealKiller() == playerId); - if (count < 1) return string.Empty; - return ColorString(new Color32(255, 69, 0, byte.MaxValue), string.Format(GetString("KillCount"), count)); + if (!Main.PlayerStates.Any(x => x.Value.GetRealKiller() == playerId) && !ffa) return string.Empty; + return ' ' + ColorString(new Color32(255, 69, 0, byte.MaxValue), string.Format(GetString("KillCount"), Main.PlayerStates.Count(x => x.Value.GetRealKiller() == playerId))); } public static string GetVitalText(byte playerId, bool RealKillerColor = false) { @@ -1429,15 +1429,17 @@ public static class Utils SendMessage(GetString("CantUse.lastroles"), PlayerId); return; } + var sb = new StringBuilder(); - sb.Append(GetString("PlayerInfo")).Append(':'); + sb.Append("Role Summary:"); + List cloneRoles = new(Main.PlayerStates.Keys); for (int i = 0; i < Main.winnerList.Count; i++) { byte id = Main.winnerList[i]; if (EndGamePatch.SummaryText[id].Contains("")) continue; - sb.Append($"\n★ ").Append(EndGamePatch.SummaryText[id].RemoveHtmlTags()); + sb.Append($"\n★ ").Append(EndGamePatch.SummaryText[id]/*.RemoveHtmlTags()*/); cloneRoles.Remove(id); } if (Options.CurrentGameMode == CustomGameMode.SoloKombat) @@ -1450,10 +1452,11 @@ public static class Utils } list.Sort(); + for (int i1 = 0; i1 < list.Count; i1++) { (int, byte) id = list[i1]; - sb.Append($"\n ").Append(EndGamePatch.SummaryText[id.Item2]); + sb.Append($"\n  ").Append(EndGamePatch.SummaryText[id.Item2]); } } else if (Options.CurrentGameMode == CustomGameMode.FFA) @@ -1466,10 +1469,11 @@ public static class Utils } list.Sort(); + for (int i1 = 0; i1 < list.Count; i1++) { (int, byte) id = list[i1]; - sb.Append($"\n ").Append(EndGamePatch.SummaryText[id.Item2]); + sb.Append($"\n  ").Append(EndGamePatch.SummaryText[id.Item2]); } } else @@ -1478,10 +1482,12 @@ public static class Utils { byte id = cloneRoles[i]; if (EndGamePatch.SummaryText[id].Contains("")) continue; - sb.Append($"\n ").Append(EndGamePatch.SummaryText[id].RemoveHtmlTags()); + sb.Append($"\n  ").Append(EndGamePatch.SummaryText[id]/*.RemoveHtmlTags()*/); } } - SendMessage(sb.ToString(), PlayerId); + sb.Append(""); + + SendMessage("\n", PlayerId, sb.ToString()); } public static void ShowKillLog(byte PlayerId = byte.MaxValue) { @@ -1500,10 +1506,11 @@ public static class Utils return; } var sb = new StringBuilder(); - if (SetEverythingUpPatch.LastWinsText != string.Empty) sb.Append($"{GetString("LastResult")}: {SetEverythingUpPatch.LastWinsText}"); - if (SetEverythingUpPatch.LastWinsReason != string.Empty) sb.Append($"\n{GetString("LastEndReason")}: {SetEverythingUpPatch.LastWinsReason}"); - if (sb.Length > 0 && Options.CurrentGameMode != CustomGameMode.SoloKombat && Options.CurrentGameMode != CustomGameMode.FFA) SendMessage(sb.ToString(), PlayerId); + if (SetEverythingUpPatch.LastWinsText != string.Empty) sb.Append($"{GetString("LastResult")} {SetEverythingUpPatch.LastWinsText}"); + if (SetEverythingUpPatch.LastWinsReason != string.Empty) sb.Append($"\n{GetString("LastEndReason")} {SetEverythingUpPatch.LastWinsReason}"); + if (sb.Length > 0 && Options.CurrentGameMode != CustomGameMode.SoloKombat && Options.CurrentGameMode != CustomGameMode.FFA) SendMessage("\n", PlayerId, sb.ToString()); } + public static string EmptyMessage() => "."; public static string GetSubRolesText(byte id, bool disableColor = false, bool intro = false, bool summary = false) { var SubRoles = Main.PlayerStates[id].SubRoles; @@ -2083,7 +2090,7 @@ public static class Utils if (seer.GetCustomRole().IsImpostor()) { if (!isForMeeting && MeetingStates.FirstMeeting && Options.ChangeNameToRoleInfo.GetBool() && Options.CurrentGameMode != CustomGameMode.FFA) - SeerRealName = $"" + GetString("YouAreImpostor") + $"\n" + seer.GetRoleInfo() + $""; + SeerRealName = $""/* + GetString("YouAreImpostor")*/ + $"\n" + seer.GetRoleInfo() + $""; } if (seer.GetCustomRole().IsNeutral() && !seer.GetCustomRole().IsMadmate()) { @@ -2887,7 +2894,7 @@ public static class Utils } if (Options.CurrentGameMode == CustomGameMode.FFA) { - summary = $"{ColorString(Main.PlayerColors[id], name)} {GetKillCountText(id)}"; + summary = $"{ColorString(Main.PlayerColors[id], name)} {GetKillCountText(id, ffa: true)}"; } return check && GetDisplayRoleName(id, true).RemoveHtmlTags().Contains("INVALID:NotAssigned") ? "INVALID" @@ -2962,7 +2969,7 @@ public static class Utils } public static string ColorString(Color32 color, string str) => $"{str}"; /// - /// Darkness:1の比率で黒色と元の色を混ぜる。マイナスだと白色と混ぜる。 + /// Darkness:Mix black and original color in a ratio of 1. If it is negative, it will be mixed with white. /// public static Color ShadeColor(this Color color, float Darkness = 0) { diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 4b6773a11..baa1fcc9b 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -80,11 +80,12 @@ internal class ChatCommands Main.isChatCommand = true; switch (args[0]) { + case "/w": case "/win": case "/winner": canceled = true; if (!Main.winnerNameList.Any()) Utils.SendMessage(GetString("NoInfoExists")); - else Utils.SendMessage("Winners:\n" + string.Join(",", Main.winnerNameList)); + else Utils.SendMessage("Winners:\n" + string.Join(", ", Main.winnerNameList)); break; case "/l": diff --git a/Patches/ChatControlPatch.cs b/Patches/ChatControlPatch.cs index db66a2762..02507d526 100644 --- a/Patches/ChatControlPatch.cs +++ b/Patches/ChatControlPatch.cs @@ -144,7 +144,7 @@ public class ChatManager public static void SendPreviousMessagesToAll(bool realMessagesOnly = false) { ChatUpdatePatch.DoBlockChat = true; - string msg = "."; + string msg = Utils.EmptyMessage(); List roles = Enum.GetValues(typeof(CustomRoles)).Cast().Where(x => x is not CustomRoles.KB_Normal and not CustomRoles.Killer).ToList(); string[] specialTexts = new string[] { "bet", "bt", "guess", "gs", "shoot", "st", "赌", "猜", "审判", "tl", "判", "审", "trial" }; var totalAlive = Main.AllAlivePlayerControls.Count; diff --git a/Patches/CheckGameEndPatch.cs b/Patches/CheckGameEndPatch.cs index 31599f210..a96e03587 100644 --- a/Patches/CheckGameEndPatch.cs +++ b/Patches/CheckGameEndPatch.cs @@ -74,7 +74,7 @@ class GameEndChecker break; case CustomWinner.CursedSoul: Main.AllPlayerControls - .Where(pc => pc.Is(CustomRoles.CursedSoul) || pc.Is(CustomRoles.Soulless) && !pc.Is(CustomRoles.Rogue) && !pc.Is(CustomRoles.Admired)) + .Where(pc => pc.Is(CustomRoles.CursedSoul) || pc.Is(CustomRoles.Soulless) && CursedSoul.SoullessWinsWithCS.GetBool() && !pc.Is(CustomRoles.Rogue) && !pc.Is(CustomRoles.Admired)) .Do(pc => CustomWinnerHolder.WinnerIds.Add(pc.PlayerId)); break; case CustomWinner.Infectious: @@ -218,9 +218,9 @@ class GameEndChecker } //恋人抢夺胜利 - if (CustomRolesHelper.RoleExist(CustomRoles.Lovers) && !reason.Equals(GameOverReason.HumansByTask) && !(!Main.LoversPlayers.ToArray().All(p => p.IsAlive()) && Options.LoverSuicide.GetBool()) && CustomWinnerHolder.WinnerTeam is CustomWinner.Crewmate or CustomWinner.Impostor or CustomWinner.Jackal or CustomWinner.Pelican) + if (CustomRolesHelper.RoleExist(CustomRoles.Lovers) && !reason.Equals(GameOverReason.HumansByTask) && !(!Main.LoversPlayers.All(p => p.IsAlive()) && Options.LoverSuicide.GetBool()) && CustomWinnerHolder.WinnerTeam is CustomWinner.Crewmate or CustomWinner.Impostor or CustomWinner.Jackal or CustomWinner.Pelican) { - CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Lovers); + /*CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Lovers);*/ CustomWinnerHolder.AdditionalWinnerTeams.Add(AdditionalWinners.Lovers); Main.AllPlayerControls .Where(p => p.Is(CustomRoles.Lovers)) .Do(p => CustomWinnerHolder.WinnerIds.Add(p.PlayerId)); @@ -233,8 +233,8 @@ class GameEndChecker { if (CustomWinnerHolder.WinnerIds.Any(x => GetPlayerById(x).Is(CustomRoles.Lovers))) { - CustomWinnerHolder.WinnerIds.Add(pc.PlayerId); - CustomWinnerHolder.AdditionalWinnerTeams.Add(AdditionalWinners.Lovers); + if (!CustomWinnerHolder.WinnerIds.Contains(pc.PlayerId)) CustomWinnerHolder.WinnerIds.Add(pc.PlayerId); + if (!CustomWinnerHolder.AdditionalWinnerTeams.Contains(AdditionalWinners.Lovers)) CustomWinnerHolder.AdditionalWinnerTeams.Add(AdditionalWinners.Lovers); } } } diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index ba8579d44..e0ad538a6 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -201,6 +201,7 @@ class HudManagerPatch case CustomRoles.BallLightning: __instance.KillButton?.OverrideText(GetString("BallLightningButtonText")); break; + case CustomRoles.Sapper: case CustomRoles.Bomber: case CustomRoles.Nuker: if (Options.UsePets.GetBool()) __instance.PetButton?.OverrideText(GetString("BomberShapeshiftText")); diff --git a/Patches/HudSpritePatch.cs b/Patches/HudSpritePatch.cs index ae6e39062..9e4cafbd8 100644 --- a/Patches/HudSpritePatch.cs +++ b/Patches/HudSpritePatch.cs @@ -127,6 +127,7 @@ public static class HudSpritePatch case CustomRoles.Jailor: newKillButton = CustomButton.Get("Jail"); break; + case CustomRoles.Sapper: case CustomRoles.Bomber: case CustomRoles.Nuker: if (Options.UsePets.GetBool()) diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index 7ddd01725..bc2eb2a83 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -1204,63 +1204,78 @@ class MeetingHudUpdatePatch public static void Postfix(MeetingHud __instance) { - // Meeting Skip with vote counting on keystroke (m + delete) - if (AmongUsClient.Instance.AmHost && Input.GetKeyDown(KeyCode.F6)) + try { - __instance.CheckForEndVoting(); - } - - if (Options.DisableCrackedGlass.GetBool()) __instance.CrackedGlass = null; - - if (AmongUsClient.Instance.AmHost && Input.GetMouseButtonUp(1) && Input.GetKey(KeyCode.LeftControl)) - { - __instance.playerStates.DoIf(x => x.HighlightedFX.enabled, x => + // Meeting Skip with vote counting on keystroke (m + delete) + if (AmongUsClient.Instance.AmHost && Input.GetKeyDown(KeyCode.F6)) { - var player = Utils.GetPlayerById(x.TargetPlayerId); - if (player != null && !player.Data.IsDead) + __instance.CheckForEndVoting(); + } + + //if (Options.DisableCrackedGlass.GetBool()) __instance.CrackedGlass = null; + + if (AmongUsClient.Instance.AmHost && Input.GetMouseButtonUp(1) && Input.GetKey(KeyCode.LeftControl)) + { + __instance.playerStates.DoIf(x => x.HighlightedFX.enabled, x => { - Main.PlayerStates[player.PlayerId].deathReason = PlayerState.DeathReason.Execution; - player.RpcExileV2(); - Main.PlayerStates[player.PlayerId].SetDead(); - Utils.SendMessage(string.Format(GetString("Message.Executed"), player.Data.PlayerName)); - Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()}を処刑しました", "Execution"); - __instance.CheckForEndVoting(); - } - }); + var player = Utils.GetPlayerById(x.TargetPlayerId); + if (player != null && !player.Data.IsDead) + { + Main.PlayerStates[player.PlayerId].deathReason = PlayerState.DeathReason.Execution; + player.RpcExileV2(); + Main.PlayerStates[player.PlayerId].SetDead(); + Utils.SendMessage(string.Format(GetString("Message.Executed"), player.Data.PlayerName)); + Logger.Info($"{player.GetNameWithRole().RemoveHtmlTags()}を処刑しました", "Execution"); + __instance.CheckForEndVoting(); + } + }); + } + + //投票结束时销毁全部技能按钮 + if (!GameStates.IsVoting && __instance.lastSecond < 1) + { + if (GameObject.Find("ShootButton") != null) ClearShootButton(__instance, true); + return; + } + + //会议技能UI处理 + bufferTime--; + if (bufferTime < 0 && __instance.discussionTimer > 0) + { + bufferTime = 10; + var myRole = PlayerControl.LocalPlayer.GetCustomRole(); + + //若某玩家死亡则修复会议该玩家状态 + __instance.playerStates.Where(x => (!Main.PlayerStates.TryGetValue(x.TargetPlayerId, out var ps) || ps.IsDead) && !x.AmDead).Do(x => x.SetDead(x.DidReport, true)); + + //若玩家死亡则销毁技能按钮 + if (myRole is CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Judge or CustomRoles.NiceSwapper or CustomRoles.Councillor or CustomRoles.Guesser && !PlayerControl.LocalPlayer.IsAlive()) + ClearShootButton(__instance, true); + + //若黑手党死亡则创建技能按钮 + if (myRole is CustomRoles.Mafia && !PlayerControl.LocalPlayer.IsAlive() && GameObject.Find("ShootButton") == null) + MafiaRevengeManager.CreateJudgeButton(__instance); + if (myRole is CustomRoles.Retributionist && !PlayerControl.LocalPlayer.IsAlive() && GameObject.Find("ShootButton") == null) + RetributionistRevengeManager.CreateJudgeButton(__instance); + //if (myRole is CustomRoles.NiceSwapper && PlayerControl.LocalPlayer.IsAlive()) + // NiceSwapper.CreateSwapperButton(__instance); + + //销毁死亡玩家身上的技能按钮 + ClearShootButton(__instance); + + } } - - //投票结束时销毁全部技能按钮 - if (!GameStates.IsVoting && __instance.lastSecond < 1) + catch (Exception ex) { - if (GameObject.Find("ShootButton") != null) ClearShootButton(__instance, true); - return; - } - - //会议技能UI处理 - bufferTime--; - if (bufferTime < 0 && __instance.discussionTimer > 0) - { - bufferTime = 10; - var myRole = PlayerControl.LocalPlayer.GetCustomRole(); - - //若某玩家死亡则修复会议该玩家状态 - __instance.playerStates.Where(x => (!Main.PlayerStates.TryGetValue(x.TargetPlayerId, out var ps) || ps.IsDead) && !x.AmDead).Do(x => x.SetDead(x.DidReport, true)); - - //若玩家死亡则销毁技能按钮 - if (myRole is CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Judge or CustomRoles.NiceSwapper or CustomRoles.Councillor or CustomRoles.Guesser && !PlayerControl.LocalPlayer.IsAlive()) - ClearShootButton(__instance, true); - - //若黑手党死亡则创建技能按钮 - if (myRole is CustomRoles.Mafia && !PlayerControl.LocalPlayer.IsAlive() && GameObject.Find("ShootButton") == null) - MafiaRevengeManager.CreateJudgeButton(__instance); - if (myRole is CustomRoles.Retributionist && !PlayerControl.LocalPlayer.IsAlive() && GameObject.Find("ShootButton") == null) - RetributionistRevengeManager.CreateJudgeButton(__instance); - //if (myRole is CustomRoles.NiceSwapper && PlayerControl.LocalPlayer.IsAlive()) - // NiceSwapper.CreateSwapperButton(__instance); - - //销毁死亡玩家身上的技能按钮 - ClearShootButton(__instance); - + Logger.Fatal(ex.ToString(), "MeetingHudUpdatePatch.Postfix"); + Logger.Warn("All Players and their info:", "Debug for Fatal Error"); + for (int i = 0; i < Main.AllPlayerControls.Count; i++) + { + PlayerControl pc = Main.AllPlayerControls[i]; + Logger.Info($" {(pc.IsAlive() ? "Alive" : $"Dead ({Main.PlayerStates[pc.PlayerId].deathReason})")}, {Utils.GetProgressText(pc)}, {Utils.GetVitalText(pc.PlayerId)}", $"{pc.GetNameWithRole()} / {pc.PlayerId}"); + } + Logger.Warn("-----------------", "Debug for Fatal Error"); + Logger.SendInGame("An error occured with this meeting. Please use /dump and send the log to the developer.\nSorry for the inconvenience."); } } } diff --git a/Patches/OutroPatch.cs b/Patches/OutroPatch.cs index bfce2e254..8e0c4cdaa 100644 --- a/Patches/OutroPatch.cs +++ b/Patches/OutroPatch.cs @@ -33,9 +33,9 @@ class EndGamePatch if (date == DateTime.MinValue) continue; var killerId = kvp.Value.GetRealKiller(); var targetId = kvp.Key; - sb.Append($"\n{date:T} {Main.AllPlayerNames[targetId]}({Utils.GetDisplayRoleName(targetId, true)}{Utils.GetSubRolesText(targetId, summary: true)}) [{Utils.GetVitalText(kvp.Key)}]"); + sb.Append($"\n{date:T} {Main.AllPlayerNames[targetId]} ({Utils.GetDisplayRoleName(targetId, true)}{Utils.GetSubRolesText(targetId, summary: true)}) [{Utils.GetVitalText(kvp.Key)}]"); if (killerId != byte.MaxValue && killerId != targetId) - sb.Append($"\n\t⇐ {Main.AllPlayerNames[killerId]}({Utils.GetDisplayRoleName(killerId, true)}{Utils.GetSubRolesText(killerId, summary: true)})"); + sb.Append($"\n\t⇐ {Main.AllPlayerNames[killerId]} ({Utils.GetDisplayRoleName(killerId, true)}{Utils.GetSubRolesText(killerId, summary: true)})"); } KillLog = sb.ToString(); if (!KillLog.Contains('\n')) KillLog = string.Empty; @@ -229,7 +229,7 @@ class SetEverythingUpPatch EndOfText: - LastWinsText = WinnerText.text.RemoveHtmlTags(); + LastWinsText = WinnerText.text/*.RemoveHtmlTags()*/; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -284,7 +284,7 @@ class SetEverythingUpPatch { byte id = cloneRoles[i]; if (EndGamePatch.SummaryText[id].Contains("")) continue; - sb.Append($"\n").Append(EndGamePatch.SummaryText[id]); + sb.Append('\n').Append(EndGamePatch.SummaryText[id]); } } var RoleSummary = RoleSummaryObject.GetComponent(); diff --git a/Patches/PetActionsPatch.cs b/Patches/PetActionsPatch.cs index 488dbb729..f8e550a63 100644 --- a/Patches/PetActionsPatch.cs +++ b/Patches/PetActionsPatch.cs @@ -1,5 +1,7 @@ using HarmonyLib; +using MS.Internal.Xml.XPath; using System; +using System.Collections.Generic; using System.Linq; using TOHE.Modules; using TOHE.Roles.Crewmate; @@ -18,7 +20,7 @@ namespace TOHE; [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.TryPet))] class LocalPetPatch { - private static readonly System.Collections.Generic.Dictionary LastProcess = new(); + private static readonly Dictionary LastProcess = new(); public static bool Prefix(PlayerControl __instance) { if (!Options.UsePets.GetBool()) return true; @@ -48,6 +50,7 @@ class LocalPetPatch [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.HandleRpc))] class ExternalRpcPetPatch { + private static readonly Dictionary LastProcess = new(); public static void Prefix(PlayerPhysics __instance, [HarmonyArgument(0)] byte callID) { if (!Options.UsePets.GetBool() || !AmongUsClient.Instance.AmHost || (RpcCalls)callID != RpcCalls.Pet) return; @@ -70,6 +73,10 @@ class ExternalRpcPetPatch && pc.GetCustomRole().PetActivatedAbility()) physics.CancelPet(); + if (!LastProcess.ContainsKey(pc.PlayerId)) LastProcess.TryAdd(pc.PlayerId, Utils.GetTimeStamp() - 2); + if (LastProcess[pc.PlayerId] + 1 >= Utils.GetTimeStamp()) return; + LastProcess[pc.PlayerId] = Utils.GetTimeStamp(); + Logger.Info($"Player {pc.GetNameWithRole().RemoveHtmlTags()} petted their pet", "PetActionTrigger"); _ = new LateTask(() => { OnPetUse(pc); }, 0.2f, $"OnPetUse: {pc.GetNameWithRole().RemoveHtmlTags()}", false); @@ -332,13 +339,14 @@ class ExternalRpcPetPatch Sniper.OnShapeshift(pc, !Sniper.IsAim[pc.PlayerId]); break; case CustomRoles.Warlock: + if (!Main.isCurseAndKill.ContainsKey(pc.PlayerId)) Main.isCurseAndKill[pc.PlayerId] = false; if (Main.CursedPlayers[pc.PlayerId] != null)//呪われた人がいるか確認 { if (!Main.CursedPlayers[pc.PlayerId].Data.IsDead) { var cp = Main.CursedPlayers[pc.PlayerId]; UnityEngine.Vector2 cppos = cp.transform.position; - System.Collections.Generic.Dictionary cpdistance = new(); + Dictionary cpdistance = new(); float dis; for (int i = 0; i < Main.AllAlivePlayerControls.Count; i++) { diff --git a/Patches/PlayerContorolPatch.cs b/Patches/PlayerContorolPatch.cs index 85553f1cb..e5e4004b0 100644 --- a/Patches/PlayerContorolPatch.cs +++ b/Patches/PlayerContorolPatch.cs @@ -352,11 +352,15 @@ class CheckMurderPatch break; case CustomRoles.Puppeteer: if (target.Is(CustomRoles.Needy) || target.Is(CustomRoles.Lazy) || Medic.ProtectList.Contains(target.PlayerId)) return false; - Main.PuppeteerList[target.PlayerId] = killer.PlayerId; - killer.SetKillCooldown(); - killer.RPCPlayCustomSound("Line"); - NotifyRoles(SpecifySeer: killer); - return false; + if (killer.CheckDoubleTrigger(target, () => + { + Main.PuppeteerList[target.PlayerId] = killer.PlayerId; + Main.PuppeteerDelayList[target.PlayerId] = GetTimeStamp(); + killer.SetKillCooldown(time: Options.PuppeteerCD.GetFloat()); + killer.RPCPlayCustomSound("Line"); + NotifyRoles(SpecifySeer: killer); + })) return false; + break; //case CustomRoles.NWitch: // // if (target.Is(CustomRoles.Needy) || target.Is(CustomRoles.Lazy)) return false; // Main.TaglockedList[target.PlayerId] = killer.PlayerId; @@ -1210,40 +1214,40 @@ class MurderPlayerPatch } } } + +// Triggered when the shapeshifter selects a target [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CheckShapeshift))] class CheckShapeshiftPatch { - public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) + public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, [HarmonyArgument(1)] bool shouldAnimate) { - Logger.Info($"Check Shapeshift Trigger - __instance: {__instance}, target: {target}, shouldAnimate: {shouldAnimate}", "Prefix"); - } - public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) - { - Logger.Info($"Check Shapeshift Trigger - __instance: {__instance}, target: {target}, shouldAnimate: {shouldAnimate}", "Postfix"); + return ShapeshiftPatch.ProcessShapeshift(__instance, target); // return false to cancel the shapeshift } } [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdCheckShapeshift))] class CmdCheckShapeshiftPatch { - public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) + public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, [HarmonyArgument(1)] bool shouldAnimate) { - CheckShapeshiftPatch.Prefix(__instance, target, shouldAnimate); - } - public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) - { - CheckShapeshiftPatch.Postfix(__instance, target, shouldAnimate); + return CheckShapeshiftPatch.Prefix(__instance, target, shouldAnimate); } } + +// Triggered when the egg animation starts playing [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.Shapeshift))] class ShapeshiftPatch { - public static bool Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, [HarmonyArgument(1)] ref bool animate) + public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target) + { + + } + + public static bool ProcessShapeshift(PlayerControl shapeshifter, PlayerControl target) { if (!Main.ProcessShapeshifts) return true; - Logger.Info($"{__instance?.GetNameWithRole()} => {target?.GetNameWithRole()}", "Shapeshift"); + Logger.Info($"{shapeshifter?.GetNameWithRole()} => {target?.GetNameWithRole()}", "Shapeshift"); - var shapeshifter = __instance; var shapeshifting = shapeshifter.PlayerId != target.PlayerId; if (Main.CheckShapeshift.TryGetValue(shapeshifter.PlayerId, out var last) && last == shapeshifting) @@ -1258,35 +1262,33 @@ class ShapeshiftPatch if (Sniper.IsEnable) Sniper.OnShapeshift(shapeshifter, shapeshifting); if (!AmongUsClient.Instance.AmHost) return true; - if (!shapeshifting) Camouflage.RpcSetSkin(__instance); + if (!shapeshifting) Camouflage.RpcSetSkin(shapeshifter); bool isSSneeded = true; if (!Pelican.IsEaten(shapeshifter.PlayerId) && !GameStates.IsVoting) + { switch (shapeshifter.GetCustomRole()) { case CustomRoles.EvilTracker: EvilTracker.OnShapeshift(shapeshifter, target, shapeshifting); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Evil Tracker RpcRevertShapeshift"); - } + 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.FireWorks: FireWorks.ShapeShiftState(shapeshifter, shapeshifting); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "FireWorks RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Sapper: Sapper.OnShapeshift(shapeshifter); + isSSneeded = false; break; case CustomRoles.Warlock: if (Main.CursedPlayers[shapeshifter.PlayerId] != null)//呪われた人がいるか確認 @@ -1322,7 +1324,7 @@ class ShapeshiftPatch shapeshifter.SetKillCooldown(); shapeshifter.Notify(GetString("WarlockControlKill")); } - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Warlock RpcRevertShapeshift"); + //_ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Warlock RpcRevertShapeshift"); } else { @@ -1332,6 +1334,7 @@ class ShapeshiftPatch } Main.CursedPlayers[shapeshifter.PlayerId] = null; } + isSSneeded = false; break; case CustomRoles.Escapee: if (shapeshifting) @@ -1349,10 +1352,7 @@ class ShapeshiftPatch Main.EscapeeLocation.Add(shapeshifter.PlayerId, shapeshifter.GetTruePosition()); } } - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Escapist RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Miner: if (Main.LastEnteredVent.ContainsKey(shapeshifter.PlayerId)) @@ -1363,10 +1363,7 @@ class ShapeshiftPatch Logger.Msg($"{shapeshifter.GetNameWithRole().RemoveHtmlTags()}:{position}", "MinerTeleport"); TP(shapeshifter.NetTransform, new Vector2(position.x, position.y)); } - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Miner RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Bomber: if (shapeshifting) @@ -1397,14 +1394,15 @@ class ShapeshiftPatch Main.PlayerStates[shapeshifter.PlayerId].deathReason = PlayerState.DeathReason.Bombed; shapeshifter.Kill(shapeshifter); } - else - { - shapeshifter.CmdCheckRevertShapeshift(false); - } + //else + //{ + // shapeshifter.CmdCheckRevertShapeshift(false); + //} NotifyRoles(); }, 1.5f, "Bomber Suiscide"); } - if (Options.BomberDiesInExplosion.GetBool()) isSSneeded = false; + isSSneeded = false; + //if (Options.BomberDiesInExplosion.GetBool()) isSSneeded = false; break; case CustomRoles.Nuker: if (shapeshifting) @@ -1435,10 +1433,10 @@ class ShapeshiftPatch Main.PlayerStates[shapeshifter.PlayerId].deathReason = PlayerState.DeathReason.Bombed; shapeshifter.Kill(shapeshifter); } - else if (!shapeshifter.IsModClient()) - { - shapeshifter.CmdCheckRevertShapeshift(false); - } + //else if (!shapeshifter.IsModClient()) + //{ + // shapeshifter.CmdCheckRevertShapeshift(false); + //} NotifyRoles(); }, 1.5f, "Nuke"); } @@ -1446,13 +1444,11 @@ class ShapeshiftPatch break; case CustomRoles.Assassin: Assassin.OnShapeshift(shapeshifter, shapeshifting); + isSSneeded = false; break; case CustomRoles.Undertaker: Undertaker.OnShapeshift(shapeshifter, shapeshifting); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Undertaker RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.ImperiusCurse: if (shapeshifting) @@ -1470,10 +1466,7 @@ class ShapeshiftPatch break; case CustomRoles.QuickShooter: QuickShooter.OnShapeshift(shapeshifter, shapeshifting); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Quick Shooter RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Camouflager: if (shapeshifting) @@ -1486,45 +1479,36 @@ class ShapeshiftPatch break; case CustomRoles.Hacker: Hacker.OnShapeshift(shapeshifter, shapeshifting, target); + isSSneeded = false; break; case CustomRoles.Disperser: if (shapeshifting) Disperser.DispersePlayers(shapeshifter); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Disperser RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Dazzler: if (shapeshifting) Dazzler.OnShapeshift(shapeshifter, target); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Dazzler RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Deathpact: if (shapeshifting) Deathpact.OnShapeshift(shapeshifter, target); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Deathpact RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Devourer: if (shapeshifting) Devourer.OnShapeshift(shapeshifter, target); - if (shapeshifting) - { - _ = new LateTask(() => { shapeshifter.CmdCheckRevertShapeshift(false); }, 1.5f, "Devourer RpcRevertShapeshift"); - } + isSSneeded = false; break; case CustomRoles.Twister: Twister.TwistPlayers(shapeshifter, shapeshifting); + isSSneeded = false; break; } + } - //変身解除のタイミングがずれて名前が直せなかった時のために強制書き換え + // 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)) { _ = new LateTask(() => @@ -1539,7 +1523,16 @@ class ShapeshiftPatch _ = new LateTask(shapeshifter.RpcResetAbilityCooldown, 0.1f, "Reset SS CD"); } - return !shapeshifting || isSSneeded || !shapeshifter.IsModClient(); + if (!isSSneeded) + { + Main.CheckShapeshift[shapeshifter.PlayerId] = false; + } + else + { + isSSneeded = !Options.DisableShapeshiftAnimations.GetBool(); + } + + return isSSneeded; } } [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.ReportDeadBody))] @@ -1795,6 +1788,7 @@ class ReportDeadBodyPatch Main.ArsonistTimer.Clear(); if (Farseer.isEnable) Main.FarseerTimer.Clear(); Main.PuppeteerList.Clear(); + Main.PuppeteerDelayList.Clear(); Main.TaglockedList.Clear(); Main.GuesserGuessed.Clear(); Main.VeteranInProtect.Clear(); @@ -2603,8 +2597,9 @@ class FixedUpdatePatch if (!player.IsAlive() || Pelican.IsEaten(player.PlayerId)) { Main.PuppeteerList.Remove(player.PlayerId); + Main.PuppeteerDelayList.Remove(player.PlayerId); } - else + else if (Main.PuppeteerDelayList[player.PlayerId] + Options.PuppeteerDelay.GetInt() < GetTimeStamp()) { Vector2 puppeteerPos = player.transform.position;//PuppeteerListのKeyの位置 Dictionary targetDistance = new(); @@ -2637,6 +2632,7 @@ class FixedUpdatePatch player.MarkDirtySettings(); target.MarkDirtySettings(); Main.PuppeteerList.Remove(player.PlayerId); + Main.PuppeteerDelayList.Remove(player.PlayerId); //Utils.NotifyRoles(); NotifyRoles(SpecifySeer: player); NotifyRoles(SpecifySeer: target); @@ -3615,6 +3611,28 @@ class PlayerControlCompleteTaskPatch } } } +[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CheckSporeTrigger))] +public static class PlayerControlCheckSporeTriggerPatch +{ + public static bool Prefix() + { + return !AmongUsClient.Instance.AmHost || !Options.DisableSporeTriggerOnFungle.GetBool(); + } +} +[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CheckUseZipline))] +public static class PlayerControlCheckUseZiplinePatch +{ + public static bool Prefix([HarmonyArgument(2)] bool fromTop) + { + if (AmongUsClient.Instance.AmHost) + { + if (Options.DisableZiplineFromTop.GetBool() && fromTop) return false; + if (Options.DisableZiplineFromUnder.GetBool() && !fromTop) return false; + } + + return true; + } +} [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.ProtectPlayer))] class PlayerControlProtectPlayerPatch { diff --git a/Patches/PlayerJoinAndLeftPatch.cs b/Patches/PlayerJoinAndLeftPatch.cs index 8c436b23e..958d69c0c 100644 --- a/Patches/PlayerJoinAndLeftPatch.cs +++ b/Patches/PlayerJoinAndLeftPatch.cs @@ -255,7 +255,7 @@ class CreatePlayerPatch }, 3f, "Welcome Message"); if (Main.OverrideWelcomeMsg == string.Empty && Main.PlayerStates.Any() && Main.clientIdList.Contains(client.Id)) { - if (Options.AutoDisplayKillLog.GetBool() && Main.PlayerStates.Any() && Main.clientIdList.Contains(client.Id)) + if (Options.AutoDisplayKillLog.GetBool()) { _ = new LateTask(() => { diff --git a/Patches/SabotageSystemPatch.cs b/Patches/SabotageSystemPatch.cs index eb90e7aaf..cebae1178 100644 --- a/Patches/SabotageSystemPatch.cs +++ b/Patches/SabotageSystemPatch.cs @@ -8,17 +8,39 @@ namespace TOHE; [HarmonyPatch(typeof(ReactorSystemType), nameof(ReactorSystemType.Deteriorate))] public static class ReactorSystemTypePatch { + private static bool SetDurationForReactorSabotage = true; public static void Prefix(ReactorSystemType __instance) { - if (!__instance.IsActive || !Options.SabotageTimeControl.GetBool()) return; + if (!Options.SabotageTimeControl.GetBool()) return; + if ((MapNames)Main.NormalOptions.MapId is MapNames.Airship) return; + + // When the sabotage ends + if (!__instance.IsActive || !SetDurationForReactorSabotage) + { + if (!SetDurationForReactorSabotage && !__instance.IsActive) + { + SetDurationForReactorSabotage = true; + } + return; + } + + Logger.Info($" {ShipStatus.Instance.Type}", "ReactorSystemTypePatch - ShipStatus.Instance.Type"); + Logger.Info($" {SetDurationForReactorSabotage}", "ReactorSystemTypePatch - SetDurationCriticalSabotage"); + SetDurationForReactorSabotage = false; switch (ShipStatus.Instance.Type) { - case ShipStatus.MapType.Pb: - if (__instance.Countdown >= Options.PolusReactorTimeLimit.GetFloat()) __instance.Countdown = Options.PolusReactorTimeLimit.GetFloat(); + case ShipStatus.MapType.Ship: //The Skeld + __instance.Countdown = Options.SkeldReactorTimeLimit.GetFloat(); return; - case ShipStatus.MapType.Hq: - if (__instance.Countdown >= Options.MiraReactorTimeLimit.GetFloat()) __instance.Countdown = Options.MiraReactorTimeLimit.GetFloat(); + case ShipStatus.MapType.Hq: //Mira HQ + __instance.Countdown = Options.MiraReactorTimeLimit.GetFloat(); + return; + case ShipStatus.MapType.Pb: //Polus + __instance.Countdown = Options.PolusReactorTimeLimit.GetFloat(); + return; + case ShipStatus.MapType.Fungle: //The Fungle + __instance.Countdown = Options.FungleReactorTimeLimit.GetFloat(); return; default: return; @@ -28,34 +50,94 @@ public static class ReactorSystemTypePatch [HarmonyPatch(typeof(HeliSabotageSystem), nameof(HeliSabotageSystem.Deteriorate))] public static class HeliSabotageSystemPatch { + private static bool SetDurationForReactorSabotage = true; public static void Prefix(HeliSabotageSystem __instance) { - if (!__instance.IsActive || !Options.SabotageTimeControl.GetBool()) + if (!Options.SabotageTimeControl.GetBool()) return; + if ((MapNames)Main.NormalOptions.MapId is not MapNames.Airship) return; + + // When the sabotage ends + if (!__instance.IsActive || ShipStatus.Instance == null || !SetDurationForReactorSabotage) + { + if (!SetDurationForReactorSabotage && !__instance.IsActive) + { + SetDurationForReactorSabotage = true; + } return; - if (ShipStatus.Instance != null && __instance.Countdown >= Options.AirshipReactorTimeLimit.GetFloat()) - __instance.Countdown = Options.AirshipReactorTimeLimit.GetFloat(); + } + + Logger.Info($" {ShipStatus.Instance.Type}", "HeliSabotageSystemPatch - ShipStatus.Instance.Type"); + Logger.Info($" {SetDurationForReactorSabotage}", "HeliSabotageSystemPatch - SetDurationCriticalSabotage"); + SetDurationForReactorSabotage = false; + + __instance.Countdown = Options.AirshipReactorTimeLimit.GetFloat(); } } [HarmonyPatch(typeof(LifeSuppSystemType), nameof(LifeSuppSystemType.Deteriorate))] public static class LifeSuppSystemTypePatch { + private static bool SetDurationForO2Sabotage = true; public static void Prefix(LifeSuppSystemType __instance) { - if (!__instance.IsActive || !Options.SabotageTimeControl.GetBool()) + if (!Options.SabotageTimeControl.GetBool()) return; + if ((MapNames)Main.NormalOptions.MapId is MapNames.Polus or MapNames.Airship or MapNames.Fungle) return; + + // When the sabotage ends + if (!__instance.IsActive || !SetDurationForO2Sabotage) + { + if (!SetDurationForO2Sabotage && !__instance.IsActive) + { + SetDurationForO2Sabotage = true; + } return; - if (ShipStatus.Instance.Type == ShipStatus.MapType.Hq && __instance.Countdown >= Options.MiraO2TimeLimit.GetFloat()) - __instance.Countdown = Options.MiraO2TimeLimit.GetFloat(); + } + + Logger.Info($" {ShipStatus.Instance.Type}", "LifeSuppSystemType - ShipStatus.Instance.Type"); + Logger.Info($" {SetDurationForO2Sabotage}", "LifeSuppSystemType - SetDurationCriticalSabotage"); + SetDurationForO2Sabotage = false; + + switch (ShipStatus.Instance.Type) + { + case ShipStatus.MapType.Ship: // The Skeld + __instance.Countdown = Options.SkeldO2TimeLimit.GetFloat(); + return; + case ShipStatus.MapType.Hq: // Mira HQ + __instance.Countdown = Options.MiraO2TimeLimit.GetFloat(); + return; + default: + return; + } } } [HarmonyPatch(typeof(MushroomMixupSabotageSystem), nameof(MushroomMixupSabotageSystem.Deteriorate))] public static class MushroomMixupSabotageSystemPatch { + private static bool SetDurationMushroomMixupSabotage = true; public static void Prefix(MushroomMixupSabotageSystem __instance) { if (Options.UsePets.GetBool()) { __instance.petEmptyChance = 0; } + + if (!Options.SabotageTimeControl.GetBool()) return; + if ((MapNames)Main.NormalOptions.MapId is not MapNames.Fungle) return; + + // When the sabotage ends + if (!__instance.IsActive || !SetDurationMushroomMixupSabotage) + { + if (!SetDurationMushroomMixupSabotage && !__instance.IsActive) + { + SetDurationMushroomMixupSabotage = true; + } + return; + } + + Logger.Info($" {ShipStatus.Instance.Type}", "MushroomMixupSabotageSystem - ShipStatus.Instance.Type"); + Logger.Info($" {SetDurationMushroomMixupSabotage}", "MushroomMixupSabotageSystem - SetDurationCriticalSabotage"); + SetDurationMushroomMixupSabotage = false; + + __instance.currentSecondsUntilHeal = Options.FungleMushroomMixupDuration.GetFloat(); } } [HarmonyPatch(typeof(ElectricTask), nameof(ElectricTask.Initialize))] diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs index ed29b663c..7ff4f18e0 100644 --- a/Patches/ShipStatusPatch.cs +++ b/Patches/ShipStatusPatch.cs @@ -14,9 +14,7 @@ class ShipFixedUpdatePatch { public static void Postfix(/*ShipStatus __instance*/) { - //ここより上、全員が実行する if (!AmongUsClient.Instance.AmHost) return; - //ここより下、ホストのみが実行する if (Main.IsFixedCooldown && Main.RefixCooldownDelay >= 0) { Main.RefixCooldownDelay -= Time.fixedDeltaTime; @@ -148,6 +146,10 @@ class RepairSystemPatch MapNames.Airship => Options.DisableAirshipCamera.GetBool(), _ => false, }; + if (camerasDisabled) + { + player.Notify(Translator.GetString("CamerasDisabledNotify"), 15f); + } return !camerasDisabled; } diff --git a/Patches/onGameStartedPatch.cs b/Patches/onGameStartedPatch.cs index 4f03a3505..c0e802f3c 100644 --- a/Patches/onGameStartedPatch.cs +++ b/Patches/onGameStartedPatch.cs @@ -58,6 +58,7 @@ internal class ChangeRoleSettings Main.isCurseAndKill = new(); Main.isCursed = false; Main.PuppeteerList = new(); + Main.PuppeteerDelayList = new(); Main.TaglockedList = new(); Main.DetectiveNotify = new(); Main.ForCrusade = new(); diff --git a/Resources/Config/EACList.txt b/Resources/Config/EACList.txt index 386ed101b..f0aa836b0 100644 --- a/Resources/Config/EACList.txt +++ b/Resources/Config/EACList.txt @@ -77,6 +77,7 @@ polkaoval#0453,自作Modな橋本環奈 ## Other tenthrope#3476,Dronecool + ## teaming and harassing hosts in multiple lobbies broadbarn#7413,niah tidytrice#2024,Alisa?(either this or above one) \ No newline at end of file diff --git a/Resources/String.csv b/Resources/String.csv index 53d6ce967..058176417 100644 --- a/Resources/String.csv +++ b/Resources/String.csv @@ -1147,6 +1147,10 @@ "RoleAssigningAlgorithm.Xorshift","Xorshift","Xorshift","Xorshift","Xorshift","Xorshift" "RoleAssigningAlgorithm.MersenneTwister","Twister","MersenneTwister","MersenneTwister","Twister","Twister" "DisableAirshipMovingPlatform","禁用移动平台(飞艇地图)","Disable Moving Platform (Airship)","Отключить движущуюся платформу (Airship)","","" +"DisableSporeTriggerOnFungle","","Disable Spore Triggers on Fungle","","","" +"DisableZiplineOnFungle","","Disable Zipline (Fungle)","","","" +"DisableZiplineFromTop","","Disable Use From Top","","","" +"DisableZiplineFromUnder","","Disable Use From Under","","","" "AirshipVariableElectrical","电气室门随机关闭(飞艇地图)","Variable Electrical (Airship)","Двери в Электрощитовой меняются случайно (Airship)","電氣室門隨機關閉(The Airship)","电气室门随机关闭(飞艇地图)" "ApplyDenyNameList","踢出使用违规昵称的玩家","Apply DenyName List","Применить файл запрещённых имён (DenyName)","踢出使用違規暱稱的玩家","踢出使用违规昵称的玩家" "KickPlayerFriendCodeNotExist","踢出没有登录的玩家","Kick players who are not logged in","Кикнуть игроков у которых нет Кода Друга","踢出沒有登入的玩家","踢出没有登录的玩家" @@ -1260,6 +1264,9 @@ "ShowArrows","","Has Arrows pointing toward bodies","","","" "ArrowDelayMin","","Minimum Arrow show-up delay","","","" "ArrowDelayMax","","Maximum Arrow show-up delay","","","" +"PuppeteerDelay","","Delay before the Puppeted Player Can Kill","","","" +"PuppeteerKCD","","Puppeteer Kill Cooldown","","","" +"PuppeteerCD","","Puppet Cooldown","","","" "DeadImpCantSabotage","内鬼死后不能破坏","Impostors can't sabotage after they've died","Мертвые Предатели не могут саботажить","内鬼死后不能破坏","" "DeadCrewCantSabotage","船员死后不能破坏","Crewmates can't sabotage after they've died","Мертвые Члены Экипажа не могут саботажить","","" "DeadNeutralCantSabotage","中立死后不能破坏","Neutrals can't sabotage after they've died","Мертвые Нейтралы не могут саботажить","","" @@ -1762,8 +1769,8 @@ "WitnessInfoLong","","(Crewmates):\nAs the Witness, when you use your kill button on someone, you will know if they killed in the last X seconds or not. (X depends on the settings)" "WitnessTime","","Max Time after killing where killer appears red","","","" "WitnessButtonText","","Examine","","","" -"WitnessFoundInnocent","","✓","","","" -"WitnessFoundKiller","","!!","","","" +"WitnessFoundInnocent","","✓","","","" +"WitnessFoundKiller","","!!","","","" "## Deadly Quota" "DeadlyQuota","","Deadly Quota","","","" @@ -1778,11 +1785,16 @@ "SabotageCooldown","更改修理时限","Sabotage Cooldown","Изменить время Саботажа","更改修理時限","更改修理时限" "SabotageTimeControl","更改修理时限","Modify Sabotage Time Limit","Изменить время Саботажа","更改修理時限","更改修理时限" "PolusReactorTimeLimit","波鲁斯抗震稳定器修理时限","Reactor Time Limit on Polus","Polus время саботажа Реактора","Polus抗震穩定器修理時限","波鲁斯抗震稳定器修理时限" +"SkeldO2TimeLimit","","O2 Time Limit on The Skeld","","","" +"SkeldReactorTimeLimit","","Reactor Time Limit on The Skeld","","","" "MiraO2TimeLimit","","O2 Time Limit on Mira HQ","","","" "MiraReactorTimeLimit","","Reactor Time Limit on Mira HQ","","","" -"MushroomMixupTime","","Mushroom Mixup Camouflage Duration","","","" +"FungleMushroomMixupDuration","","Mushroom Mixup Camouflage Duration","","","" +"FungleReactorTimeLimit","","Reactor Time Limit on Fungle","","","" "AirshipReactorTimeLimit","飞艇坠毁路线修理时限","Reactor Time Limit on Airship","Airship время саботажа Реактора","The Airship避開墜毀路線修理時限","飞艇坠毁路线修理时限" +"CamerasDisabledNotify","","Cameras are globally disabled by the host","","","" + "## 指令帮助 / Commands" "CommandList","★ 主要指令:","★ Command list:","★ Список команд:","★ 主要指令:","★ 主要指令:" "Command.now","→ 显示当前设置","→ Display active Settings","→ Показать активные настройки","→ 顯示目前設定","→ 显示当前设置" @@ -2163,8 +2175,8 @@ "Roles","职业","Roles","Роли","職業","职业" "Settings","设定","Settings","Настройки","設定","设定" "Addons","附加效果","Add-Ons","Атрибуты","附加效果","附加效果" -"LastResult"," ★ 游戏结果","★ Match Results","★ Результат матча"," ★ 遊戲結果"," ★ 游戏结果" -"LastEndReason"," ★ 结束原因","★ End Reason","★ Причина окончания"," ★ 結束原因"," ★ 结束原因" +"LastResult"," ★ 游戏结果","★ Match Results:","★ Результат матча"," ★ 遊戲結果"," ★ 游戏结果" +"LastEndReason"," ★ 结束原因","★ End Reason:","★ Причина окончания"," ★ 結束原因"," ★ 结束原因" "KillLog","击杀日志","Kill Log","История убийств","殺人紀錄","击杀日志" "Maximum","最大人数","Max","Максимум","最大人數","最大人数" "RoleRate","启用","ON","Рандом","啟用","启用" @@ -2362,19 +2374,19 @@ "OneNeutralRemain","","1 Neutral remains","","","" "IsGood","{0} 是个好人","{0} was a good guy","{0} был хорошим парнем","{0} 是個好人","{0} 是个好人" "BelongTo","{0} 属于 {1}","{0} belongs to {1}","{0} принадлежит {1}","{0} 屬於 {1}","{0} 属于 {1}" -"GameOverReason.HumansByTask","船员完成了任务","The Crewmates completed all tasks","Члены Экипажа выполнили задания","船員完成了任務","船员完成了任务" "GG","","GG! No more killers remain. Crewmates win!","","","" "## 游戏结束原因 / Game Overs" -"GameOverReason.HumansByVote","内鬼被驱逐","All Impostors and Neutral Killers were ejected or killed","Предатели были изгнаны","偽裝者被逐出","内鬼被驱逐" -"GameOverReason.HumansDisconnect","船员断线","Crewmates disconnected","Члены Экипажа вышли из игры","船員斷線","船员断线" -"GameOverReason.ImpostorByKill","内鬼人数占优","The Impostors killed everyone","Предатели убили всех","偽裝者人數占優","内鬼人数占优" -"GameOverReason.ImpostorBySabotage","内鬼破坏了设施","Crewmates failed to fix a critical sabotage.","Предатели саботировали обьект","偽裝者破壞了設施","内鬼破坏了设施" -"GameOverReason.ImpostorByVote","船员被驱逐","The Crewmates were ejected","Члены Экипажа были изгнаны","船員被逐出","船员被驱逐" -"GameOverReason.ImpostorDisconnect","内鬼断线","Impostors disconnected","Предатели вышли из игры","偽裝者斷線","内鬼断线" -"DivinatorCheck.HideMsg","{0}似乎藏着不可告人的秘密","Looks like {0} hides secrets.","Похоже, {0} скрывает секреты.","{0}似乎藏著不可告人的秘密","{0}似乎藏着不可告人的秘密" +"GameOverReason.HumansByVote","内鬼被驱逐","All Impostors and Neutral Killers were ejected or killed","Предатели были изгнаны","偽裝者被逐出","内鬼被驱逐" +"GameOverReason.HumansDisconnect","船员断线","Crewmates disconnected","Члены Экипажа вышли из игры","船員斷線","船员断线" +"GameOverReason.ImpostorByKill","内鬼人数占优","The Impostors killed everyone","Предатели убили всех","偽裝者人數占優","内鬼人数占优" +"GameOverReason.ImpostorBySabotage","内鬼破坏了设施","Crewmates failed to fix a critical sabotage","Предатели саботировали обьект","偽裝者破壞了設施","内鬼破坏了设施" +"GameOverReason.ImpostorByVote","船员被驱逐","The Crewmates were ejected","Члены Экипажа были изгнаны","船員被逐出","船员被驱逐" +"GameOverReason.ImpostorDisconnect","内鬼断线","Impostors disconnected","Предатели вышли из игры","偽裝者斷線","内鬼断线" +"GameOverReason.HumansByTask","船员完成了任务","The Crewmates completed all tasks","Члены Экипажа выполнили задания","船員完成了任務","船员完成了任务" "## 占卜师信息 / Divinator Checks" +"DivinatorCheck.HideMsg","{0}似乎藏着不可告人的秘密","Looks like {0} hides secrets.","Похоже, {0} скрывает секреты.","{0}似乎藏著不可告人的秘密","{0}似乎藏着不可告人的秘密" "DivinatorCheck.Honest","{0}似乎是个忠厚老实的人","Looks like {0} is being honest.","Похоже, {0} просто честный гражданин.","{0}似乎是個忠厚老實的人","{0}似乎是个忠厚老实的人" "DivinatorCheck.Impulse","{0}正抑制着某种冲动","Looks like {0} is suppressing some kind of impulse.","Похоже, {0} подавляет импульсы.","{0}正抑制著某種衝動","{0}正抑制着某种冲动" "DivinatorCheck.Weirdo","{0}有些突兀地混在人群中","Looks like {0} is mixed in crowd.","Похоже, {0} смешался с толпой.","{0}有些突兀的混在人群中","{0}有些突兀地混在人群中" @@ -3261,6 +3273,7 @@ "CursedSoulSoullessPlayer","灵魂被夺走","Soul snatched","Душа была похищена","","" "CursedSoulInvalidTarget","找不到灵魂","No soul found","Душа не найдена","","" "Soulless-","没有灵魂","Soulless ","Бездушный ","","" +"SoullessWinsWithCS","","Soulless Players Win With the Cursed Soul","","","" "## Admirer Text Strings" "AdmireCooldown","仰慕冷却","Admire Cooldown","","","" diff --git a/Roles/Crewmate/Addict.cs b/Roles/Crewmate/Addict.cs index 2824f0f99..9fe675c74 100644 --- a/Roles/Crewmate/Addict.cs +++ b/Roles/Crewmate/Addict.cs @@ -28,11 +28,11 @@ namespace TOHE.Roles.Crewmate .SetValueFormat(OptionFormat.Seconds); TimeLimit = FloatOptionItem.Create(Id + 12, "SerialKillerLimit", new(5f, 75f, 1f), 45f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Addict]) .SetValueFormat(OptionFormat.Seconds); - ImmortalTimeAfterVent = FloatOptionItem.Create(Id + 13, "AddictInvulnerbilityTimeAfterVent", new(5f, 30f, 1f), 10f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Addict]) + ImmortalTimeAfterVent = FloatOptionItem.Create(Id + 13, "AddictInvulnerbilityTimeAfterVent", new(0f, 30f, 1f), 10f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Addict]) .SetValueFormat(OptionFormat.Seconds); // SpeedWhileImmortal = FloatOptionItem.Create(Id + 14, "AddictSpeedWhileInvulnerble", new(0.25f, 5f, 0.25f), 1.75f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Addict]) // .SetValueFormat(OptionFormat.Multiplier); - FreezeTimeAfterImmortal = FloatOptionItem.Create(Id + 15, "AddictFreezeTimeAfterInvulnerbility", new(1f, 10f, 1f), 3f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Addict]) + FreezeTimeAfterImmortal = FloatOptionItem.Create(Id + 15, "AddictFreezeTimeAfterInvulnerbility", new(0f, 10f, 1f), 3f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Addict]) .SetValueFormat(OptionFormat.Seconds); } public static void Init() diff --git a/Roles/Crewmate/Aid.cs b/Roles/Crewmate/Aid.cs index 5b0a46c7a..206cf8120 100644 --- a/Roles/Crewmate/Aid.cs +++ b/Roles/Crewmate/Aid.cs @@ -22,9 +22,9 @@ namespace TOHE.Roles.Crewmate public static void SetupCustomOption() { SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Aid); - AidCD = FloatOptionItem.Create(Id + 10, "AidCD", new(0f, 70f, 1f), 15f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) + AidCD = FloatOptionItem.Create(Id + 10, "AidCD", new(0f, 60f, 1f), 15f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) .SetValueFormat(OptionFormat.Seconds); - AidDur = FloatOptionItem.Create(Id + 11, "AidDur", new(0f, 70f, 1f), 10f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) + AidDur = FloatOptionItem.Create(Id + 11, "AidDur", new(0f, 60f, 1f), 10f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) .SetValueFormat(OptionFormat.Seconds); UseLimitOpt = IntegerOptionItem.Create(Id + 12, "AbilityUseLimit", new(1, 20, 1), 5, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) .SetValueFormat(OptionFormat.Times); diff --git a/Roles/Crewmate/Bloodhound.cs b/Roles/Crewmate/Bloodhound.cs index e48d770b1..b1ea79527 100644 --- a/Roles/Crewmate/Bloodhound.cs +++ b/Roles/Crewmate/Bloodhound.cs @@ -28,7 +28,7 @@ ArrowsPointingToDeadBody = BooleanOptionItem.Create(Id + 10, "BloodhoundArrowsPointingToDeadBody", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Bloodhound]); LeaveDeadBodyUnreportable = BooleanOptionItem.Create(Id + 11, "BloodhoundLeaveDeadBodyUnreportable", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Bloodhound]); NotifyKiller = BooleanOptionItem.Create(Id + 14, "BloodhoundNotifyKiller", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Bloodhound]); - UseLimitOpt = IntegerOptionItem.Create(Id + 12, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Bloodhound]) + UseLimitOpt = IntegerOptionItem.Create(Id + 12, "AbilityUseLimit", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Bloodhound]) .SetValueFormat(OptionFormat.Times); BloodhoundAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 13, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 0.2f, TabGroup.CrewmateRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Bloodhound]) diff --git a/Roles/Crewmate/CameraMan.cs b/Roles/Crewmate/CameraMan.cs index 0372aa329..beea0bf9c 100644 --- a/Roles/Crewmate/CameraMan.cs +++ b/Roles/Crewmate/CameraMan.cs @@ -24,7 +24,7 @@ namespace TOHE.Roles.Crewmate SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.CameraMan); VentCooldown = FloatOptionItem.Create(Id + 10, "VentCooldown", new(0f, 70f, 1f), 15f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.CameraMan]) .SetValueFormat(OptionFormat.Seconds); - UseLimitOpt = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.CameraMan]) + UseLimitOpt = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.CameraMan]) .SetValueFormat(OptionFormat.Times); CameraManAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 12, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 1f, TabGroup.CrewmateRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.CameraMan]) @@ -69,29 +69,15 @@ namespace TOHE.Roles.Crewmate SendRPC(pc.PlayerId, true); Main.CameraManCD.TryAdd(pc.PlayerId, GetTimeStamp()); - Vector2 pos; - - switch (Main.NormalOptions.MapId) + Vector2 pos = Main.NormalOptions.MapId switch { - case 0: - pos = new(-13.5f, -5.5f); - break; - case 1: - pos = new(15.3f, 3.8f); - break; - case 2: - pos = new(3.0f, -12.0f); - break; - case 4: - pos = new(5.8f, -10.8f); - break; - case 5: - pos = new(9.5f, 1.2f); - break; - default: - TOHE.Logger.Error("Invalid MapID", "CameraMan Teleport"); - return; - } + 0 => new(-13.5f, -5.5f), + 1 => new(15.3f, 3.8f), + 2 => new(3.0f, -12.0f), + 4 => new(5.8f, -10.8f), + 5 => new(9.5f, 1.2f), + _ => throw new NotImplementedException(), + }; _ = new LateTask(() => { TP(pc.NetTransform, pos); }, UsePets.GetBool() ? 0.1f : 2f, "CameraMan Teleport"); } diff --git a/Roles/Crewmate/Chameleon.cs b/Roles/Crewmate/Chameleon.cs index d532ab71d..2dc12f676 100644 --- a/Roles/Crewmate/Chameleon.cs +++ b/Roles/Crewmate/Chameleon.cs @@ -30,7 +30,7 @@ public static class Chameleon .SetValueFormat(OptionFormat.Seconds); ChameleonDuration = FloatOptionItem.Create(Id + 3, "ChameleonDuration", new(1f, 30f, 1f), 10f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Chameleon]) .SetValueFormat(OptionFormat.Seconds); - UseLimitOpt = IntegerOptionItem.Create(Id + 4, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Chameleon]) + UseLimitOpt = IntegerOptionItem.Create(Id + 4, "AbilityUseLimit", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Chameleon]) .SetValueFormat(OptionFormat.Times); ChameleonAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 5, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 0.5f, TabGroup.CrewmateRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Chameleon]) diff --git a/Roles/Crewmate/Doormaster.cs b/Roles/Crewmate/Doormaster.cs index 998e6d93c..c3555e331 100644 --- a/Roles/Crewmate/Doormaster.cs +++ b/Roles/Crewmate/Doormaster.cs @@ -25,7 +25,7 @@ namespace TOHE.Roles.Crewmate SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Doormaster); VentCooldown = FloatOptionItem.Create(Id + 10, "VentCooldown", new(0f, 70f, 1f), 15f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Doormaster]) .SetValueFormat(OptionFormat.Seconds); - UseLimitOpt = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Doormaster]) + UseLimitOpt = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Doormaster]) .SetValueFormat(OptionFormat.Times); DoormasterAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 12, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 1f, TabGroup.CrewmateRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Doormaster]) diff --git a/Roles/Crewmate/Jailer.cs b/Roles/Crewmate/Jailer.cs index 8dd3dc7b8..36e2caffe 100644 --- a/Roles/Crewmate/Jailer.cs +++ b/Roles/Crewmate/Jailer.cs @@ -22,7 +22,7 @@ public static class Jailor public static void SetupCustomOption() { SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Jailor); - JailCooldown = FloatOptionItem.Create(Id + 10, "JailorJailCooldown", new(0f, 999f, 1f), 15f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Jailor]) + JailCooldown = FloatOptionItem.Create(Id + 10, "JailorJailCooldown", new(0f, 60f, 1f), 15f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Jailor]) .SetValueFormat(OptionFormat.Seconds); notifyJailedOnMeeting = BooleanOptionItem.Create(Id + 18, "notifyJailedOnMeeting", true, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Jailor]); } @@ -75,7 +75,7 @@ public static class Jailor byte jailerId = reader.ReadByte(); if (!setTarget) { - int points = reader.ReadInt32(); + _ = reader.ReadInt32(); //if (JailorExeLimit.ContainsKey(jailerId)) JailorExeLimit[jailerId] = points; //else JailorExeLimit.Add(jailerId, MaxExecution.GetInt()); diff --git a/Roles/Crewmate/Mediumshiper.cs b/Roles/Crewmate/Mediumshiper.cs index 4d0d229b9..f8a092903 100644 --- a/Roles/Crewmate/Mediumshiper.cs +++ b/Roles/Crewmate/Mediumshiper.cs @@ -20,7 +20,7 @@ public static class Mediumshiper public static void SetupCustomOption() { Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Mediumshiper); - ContactLimitOpt = IntegerOptionItem.Create(Id + 10, "MediumshiperContactLimit", new(1, 15, 1), 1, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mediumshiper]) + ContactLimitOpt = IntegerOptionItem.Create(Id + 10, "MediumshiperContactLimit", new(0, 15, 1), 1, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mediumshiper]) .SetValueFormat(OptionFormat.Times); OnlyReceiveMsgFromCrew = BooleanOptionItem.Create(Id + 11, "MediumshiperOnlyReceiveMsgFromCrew", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Mediumshiper]); MediumAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 12, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 1f, TabGroup.CrewmateRoles, false) diff --git a/Roles/Crewmate/Merchant.cs b/Roles/Crewmate/Merchant.cs index 30855f438..85507e492 100644 --- a/Roles/Crewmate/Merchant.cs +++ b/Roles/Crewmate/Merchant.cs @@ -88,7 +88,7 @@ namespace TOHE.Roles.Crewmate SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Merchant); OptionMaxSell = IntegerOptionItem.Create(Id + 2, "MerchantMaxSell", new(1, 20, 1), 5, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]).SetValueFormat(OptionFormat.Times); OptionMoneyPerSell = IntegerOptionItem.Create(Id + 3, "MerchantMoneyPerSell", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]).SetValueFormat(OptionFormat.Times); - OptionMoneyRequiredToBribe = IntegerOptionItem.Create(Id + 4, "MerchantMoneyRequiredToBribe", new(1, 99, 1), 5, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]).SetValueFormat(OptionFormat.Times); + OptionMoneyRequiredToBribe = IntegerOptionItem.Create(Id + 4, "MerchantMoneyRequiredToBribe", new(1, 70, 1), 5, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]).SetValueFormat(OptionFormat.Times); OptionNotifyBribery = BooleanOptionItem.Create(Id + 5, "MerchantNotifyBribery", false, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]); OptionCanTargetCrew = BooleanOptionItem.Create(Id + 6, "MerchantTargetCrew", true, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]); OptionCanTargetImpostor = BooleanOptionItem.Create(Id + 7, "MerchantTargetImpostor", true, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Merchant]); diff --git a/Roles/Crewmate/NiceSwapper.cs b/Roles/Crewmate/NiceSwapper.cs index 56e1fb9dd..76b2d007d 100644 --- a/Roles/Crewmate/NiceSwapper.cs +++ b/Roles/Crewmate/NiceSwapper.cs @@ -26,7 +26,7 @@ public static class NiceSwapper public static void SetupCustomOption() { Options.SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.NiceSwapper, 1); - SwapMax = IntegerOptionItem.Create(Id + 3, "NiceSwapperMax", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]) + SwapMax = IntegerOptionItem.Create(Id + 3, "NiceSwapperMax", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]) .SetValueFormat(OptionFormat.Times); CanSwapSelf = BooleanOptionItem.Create(Id + 2, "CanSwapSelfVotes", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]); CanStartMeeting = BooleanOptionItem.Create(Id + 4, "JesterCanUseButton", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]); diff --git a/Roles/Crewmate/ParityCop.cs b/Roles/Crewmate/ParityCop.cs index 3fdf6d53b..5e2dd55a5 100644 --- a/Roles/Crewmate/ParityCop.cs +++ b/Roles/Crewmate/ParityCop.cs @@ -35,7 +35,7 @@ public static class ParityCop SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.ParityCop); TryHideMsg = BooleanOptionItem.Create(Id + 10, "ParityCopTryHideMsg", true, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.ParityCop]) .SetColor(Color.green); - ParityCheckLimitMax = IntegerOptionItem.Create(Id + 11, "MaxParityCheckLimit", new(1, 20, 1), 2, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.ParityCop]) + ParityCheckLimitMax = IntegerOptionItem.Create(Id + 11, "MaxParityCheckLimit", new(0, 20, 1), 2, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.ParityCop]) .SetValueFormat(OptionFormat.Times); ParityCheckLimitPerMeeting = IntegerOptionItem.Create(Id + 12, "ParityCheckLimitPerMeeting", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.ParityCop]) .SetValueFormat(OptionFormat.Times); diff --git a/Roles/Crewmate/Ricochet.cs b/Roles/Crewmate/Ricochet.cs index da603592a..b8c276cb9 100644 --- a/Roles/Crewmate/Ricochet.cs +++ b/Roles/Crewmate/Ricochet.cs @@ -22,7 +22,7 @@ namespace TOHE.Roles.Crewmate public static void SetupCustomOption() { SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Ricochet, 1); - UseLimitOpt = IntegerOptionItem.Create(Id + 10, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Ricochet]) + UseLimitOpt = IntegerOptionItem.Create(Id + 10, "AbilityUseLimit", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Ricochet]) .SetValueFormat(OptionFormat.Times); RicochetAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 11, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 0.5f, TabGroup.CrewmateRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Ricochet]) diff --git a/Roles/Crewmate/Spy.cs b/Roles/Crewmate/Spy.cs index e2a1ae0d6..3a30c196c 100644 --- a/Roles/Crewmate/Spy.cs +++ b/Roles/Crewmate/Spy.cs @@ -24,7 +24,7 @@ namespace TOHE.Roles.Crewmate public static void SetupCustomOption() { SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Spy, 1); - UseLimitOpt = IntegerOptionItem.Create(Id + 10, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Spy]) + UseLimitOpt = IntegerOptionItem.Create(Id + 10, "AbilityUseLimit", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Spy]) .SetValueFormat(OptionFormat.Times); SpyRedNameDur = FloatOptionItem.Create(Id + 11, "SpyRedNameDur", new(0f, 70f, 1f), 3f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Spy]) .SetValueFormat(OptionFormat.Seconds); diff --git a/Roles/Crewmate/Tether.cs b/Roles/Crewmate/Tether.cs index b8096646d..b0f53b38b 100644 --- a/Roles/Crewmate/Tether.cs +++ b/Roles/Crewmate/Tether.cs @@ -25,7 +25,7 @@ namespace TOHE.Roles.Crewmate SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Tether, 1); VentCooldown = FloatOptionItem.Create(Id + 10, "VentCooldown", new(0f, 70f, 1f), 15f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Tether]) .SetValueFormat(OptionFormat.Seconds); - UseLimitOpt = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Tether]) + UseLimitOpt = IntegerOptionItem.Create(Id + 11, "AbilityUseLimit", new(0, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Tether]) .SetValueFormat(OptionFormat.Times); TetherAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 12, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 0.4f, TabGroup.CrewmateRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Tether]) diff --git a/Roles/Impostor/Assassin.cs b/Roles/Impostor/Assassin.cs index 0e8354bc9..797ec42b6 100644 --- a/Roles/Impostor/Assassin.cs +++ b/Roles/Impostor/Assassin.cs @@ -106,7 +106,7 @@ internal static class Assassin Utils.TP(pc.NetTransform, target.GetTruePosition()); pc.ResetKillCooldown(); pc.SyncSettings(); - pc.SetKillCooldown(); + pc.SetKillCooldown(DefaultKillCooldown); pc.RpcCheckAndMurder(target); } }, UsePets.GetBool() ? 0.1f : 1.5f, "Assassin Assassinate"); diff --git a/Roles/Impostor/Camouflager.cs b/Roles/Impostor/Camouflager.cs index 00328f915..305f3142a 100644 --- a/Roles/Impostor/Camouflager.cs +++ b/Roles/Impostor/Camouflager.cs @@ -21,7 +21,7 @@ namespace TOHE.Roles.Impostor .SetValueFormat(OptionFormat.Seconds); CamouflageDuration = FloatOptionItem.Create(Id + 3, "CamouflageDuration", new(1f, 30f, 1f), 12f, TabGroup.ImpostorRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Camouflager]) .SetValueFormat(OptionFormat.Seconds); - CamoLimitOpt = IntegerOptionItem.Create(Id + 4, "AbilityUseLimit", new(1, 5, 1), 1, TabGroup.ImpostorRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Camouflager]) + CamoLimitOpt = IntegerOptionItem.Create(Id + 4, "AbilityUseLimit", new(0, 5, 1), 1, TabGroup.ImpostorRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Camouflager]) .SetValueFormat(OptionFormat.Times); CamoAbilityUseGainWithEachKill = FloatOptionItem.Create(Id + 5, "AbilityUseGainWithEachKill", new(0f, 5f, 0.1f), 0.3f, TabGroup.ImpostorRoles, false) .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Camouflager]) diff --git a/Roles/Impostor/Dazzler.cs b/Roles/Impostor/Dazzler.cs index f810b742c..bf5a20e74 100644 --- a/Roles/Impostor/Dazzler.cs +++ b/Roles/Impostor/Dazzler.cs @@ -36,7 +36,7 @@ namespace TOHE.Roles.Impostor // .SetValueFormat(OptionFormat.Seconds); CauseVision = FloatOptionItem.Create(Id + 13, "DazzlerCauseVision", new(0f, 5f, 0.05f), 0.4f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Dazzler]) .SetValueFormat(OptionFormat.Multiplier); - DazzleLimitOpt = IntegerOptionItem.Create(Id + 14, "DazzlerDazzleLimit", new(1, 15, 1), 1, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Dazzler]) + DazzleLimitOpt = IntegerOptionItem.Create(Id + 14, "DazzlerDazzleLimit", new(0, 15, 1), 1, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Dazzler]) .SetValueFormat(OptionFormat.Times); ResetDazzledVisionOnDeath = BooleanOptionItem.Create(Id + 15, "DazzlerResetDazzledVisionOnDeath", true, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Dazzler]); DazzlerAbilityUseGainWithEachKill = FloatOptionItem.Create(Id + 16, "AbilityUseGainWithEachKill", new(0f, 5f, 0.1f), 0.5f, TabGroup.ImpostorRoles, false) diff --git a/Roles/Impostor/Devourer.cs b/Roles/Impostor/Devourer.cs index a3f4d0235..6bc24e842 100644 --- a/Roles/Impostor/Devourer.cs +++ b/Roles/Impostor/Devourer.cs @@ -8,7 +8,7 @@ namespace TOHE.Roles.Impostor { public static class Devourer { - static GameData.PlayerOutfit ConsumedOutfit = new GameData.PlayerOutfit().Set("", 15, "", "", "visor_Crack", ""); + private static readonly GameData.PlayerOutfit ConsumedOutfit = new GameData.PlayerOutfit().Set("", 15, "", "", "visor_Crack", ""); private static Dictionary OriginalPlayerSkins = new(); private static readonly int Id = 3550; diff --git a/Roles/Impostor/Disperser.cs b/Roles/Impostor/Disperser.cs index 9e3b82996..8ad22fe85 100644 --- a/Roles/Impostor/Disperser.cs +++ b/Roles/Impostor/Disperser.cs @@ -24,7 +24,7 @@ public static class Disperser .SetValueFormat(OptionFormat.Seconds); DisperserShapeshiftDuration = FloatOptionItem.Create(Id + 6, "ShapeshiftDuration", new(1f, 30f, 1f), 1f, TabGroup.OtherRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Disperser]) .SetValueFormat(OptionFormat.Seconds); - DisperserLimitOpt = IntegerOptionItem.Create(Id + 7, "AbilityUseLimit", new(1, 5, 1), 1, TabGroup.OtherRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Disperser]) + DisperserLimitOpt = IntegerOptionItem.Create(Id + 7, "AbilityUseLimit", new(0, 5, 1), 1, TabGroup.OtherRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Disperser]) .SetValueFormat(OptionFormat.Times); DisperserAbilityUseGainWithEachKill = FloatOptionItem.Create(Id + 8, "AbilityUseGainWithEachKill", new(0f, 5f, 0.1f), 0.3f, TabGroup.OtherRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Disperser]) diff --git a/Roles/Impostor/Hacker.cs b/Roles/Impostor/Hacker.cs index b29ae71c2..86e6e8045 100644 --- a/Roles/Impostor/Hacker.cs +++ b/Roles/Impostor/Hacker.cs @@ -25,7 +25,7 @@ public static class Hacker SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Hacker); KillCooldown = FloatOptionItem.Create(Id + 2, "KillCooldown", new(0f, 180f, 2.5f), 30f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Hacker]) .SetValueFormat(OptionFormat.Seconds); - HackLimitOpt = IntegerOptionItem.Create(Id + 3, "HackLimit", new(1, 5, 1), 0, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Hacker]) + HackLimitOpt = IntegerOptionItem.Create(Id + 3, "HackLimit", new(0, 5, 1), 0, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Hacker]) .SetValueFormat(OptionFormat.Times); HackerAbilityUseGainWithEachKill = FloatOptionItem.Create(Id + 4, "AbilityUseGainWithEachKill", new(0f, 5f, 0.1f), 0.2f, TabGroup.ImpostorRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Hacker]) diff --git a/Roles/Impostor/Hitman.cs b/Roles/Impostor/Hitman.cs index 934a46705..2c64b407b 100644 --- a/Roles/Impostor/Hitman.cs +++ b/Roles/Impostor/Hitman.cs @@ -88,7 +88,7 @@ namespace TOHE.Roles.Impostor targetId = target.PlayerId; SendRPC(targetId); - _ = new LateTask(() => { hitman.CmdCheckRevertShapeshift(false); }, 1.5f, "Hitman RpcRevertShapeshift"); + //_ = new LateTask(() => { hitman.CmdCheckRevertShapeshift(false); }, 1.5f, "Hitman RpcRevertShapeshift"); } public static string GetProgressText() diff --git a/Roles/Impostor/Lurker.cs b/Roles/Impostor/Lurker.cs index 2a9ef9832..fc3128045 100644 --- a/Roles/Impostor/Lurker.cs +++ b/Roles/Impostor/Lurker.cs @@ -17,7 +17,7 @@ namespace TOHE.Roles.Impostor SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Lurker); DefaultKillCooldown = FloatOptionItem.Create(Id + 10, "SansDefaultKillCooldown", new(20f, 180f, 1f), 30f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Lurker]) .SetValueFormat(OptionFormat.Seconds); - ReduceKillCooldown = FloatOptionItem.Create(Id + 11, "SansReduceKillCooldown", new(0f, 10f, 1f), 2f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Lurker]) + ReduceKillCooldown = FloatOptionItem.Create(Id + 11, "SansReduceKillCooldown", new(0f, 10f, 1f), 1f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Lurker]) .SetValueFormat(OptionFormat.Seconds); } public static void Init() diff --git a/Roles/Impostor/RiftMaker.cs b/Roles/Impostor/RiftMaker.cs index 66cda91c8..e6df45fd1 100644 --- a/Roles/Impostor/RiftMaker.cs +++ b/Roles/Impostor/RiftMaker.cs @@ -116,7 +116,7 @@ namespace TOHE.Roles.Impostor if (Marks.Count == 2) LastTP = GetTimeStamp(); player.Notify(GetString("MarkDone")); - if (!isPet) _ = new LateTask(() => { player.CmdCheckRevertShapeshift(false); }, 1.5f, "Rift Maker RpcRevertShapeshift"); + //if (!isPet) _ = new LateTask(() => { player.CmdCheckRevertShapeshift(false); }, 1.5f, "Rift Maker RpcRevertShapeshift"); } public static string GetProgressText() diff --git a/Roles/Impostor/Sapper.cs b/Roles/Impostor/Sapper.cs index a1fb83c84..92278d247 100644 --- a/Roles/Impostor/Sapper.cs +++ b/Roles/Impostor/Sapper.cs @@ -59,7 +59,7 @@ namespace TOHE.Roles.Impostor Bombs.TryAdd(pc.transform.position, GetTimeStamp()); Main.SapperCD.TryAdd(pc.PlayerId, GetTimeStamp()); - if (!isPet) _ = new LateTask(() => { pc.CmdCheckRevertShapeshift(false); }, 1.5f, "Sapper RpcRevertShapeshift"); + //if (!isPet) _ = new LateTask(() => { pc.CmdCheckRevertShapeshift(false); }, 1.5f, "Sapper RpcRevertShapeshift"); } public static void OnFixedUpdate(PlayerControl pc) diff --git a/Roles/Impostor/Swooper.cs b/Roles/Impostor/Swooper.cs index 53c7d166c..abf3f2bd4 100644 --- a/Roles/Impostor/Swooper.cs +++ b/Roles/Impostor/Swooper.cs @@ -34,7 +34,7 @@ public static class Swooper SwooperDuration = FloatOptionItem.Create(Id + 3, "SwooperDuration", new(1f, 30f, 1f), 10f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Swooper]) .SetValueFormat(OptionFormat.Seconds); SwooperVentNormallyOnCooldown = BooleanOptionItem.Create(Id + 4, "SwooperVentNormallyOnCooldown", true, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Swooper]); - SwooperLimitOpt = IntegerOptionItem.Create(Id + 5, "AbilityUseLimit", new(1, 5, 1), 1, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Swooper]) + SwooperLimitOpt = IntegerOptionItem.Create(Id + 5, "AbilityUseLimit", new(0, 5, 1), 1, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Swooper]) .SetValueFormat(OptionFormat.Times); SwooperAbilityUseGainWithEachKill = FloatOptionItem.Create(Id + 6, "AbilityUseGainWithEachKill", new(0f, 5f, 0.1f), 0.5f, TabGroup.ImpostorRoles, false) .SetParent(CustomRoleSpawnChances[CustomRoles.Swooper]) diff --git a/Roles/Impostor/Undertaker.cs b/Roles/Impostor/Undertaker.cs index 75fdd6cf6..1f00a555b 100644 --- a/Roles/Impostor/Undertaker.cs +++ b/Roles/Impostor/Undertaker.cs @@ -22,7 +22,7 @@ internal static class Undertaker public static void SetupCustomOption() { SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Undertaker); - MarkCooldown = FloatOptionItem.Create(Id + 10, "UndertakerMarkCooldown", new(0f, 180f, 0.5f), 1, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Undertaker]) + MarkCooldown = FloatOptionItem.Create(Id + 10, "UndertakerMarkCooldown", new(0f, 180f, 0.5f), 1f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Undertaker]) .SetValueFormat(OptionFormat.Seconds); AssassinateCooldown = FloatOptionItem.Create(Id + 11, "UndertakerAssassinateCooldown", new(0f, 180f, 0.5f), 18.5f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Undertaker]) .SetValueFormat(OptionFormat.Seconds); diff --git a/Roles/Neutral/Agitater.cs b/Roles/Neutral/Agitater.cs index f55badad7..1986063b2 100644 --- a/Roles/Neutral/Agitater.cs +++ b/Roles/Neutral/Agitater.cs @@ -31,7 +31,7 @@ public static class Agitater .SetValueFormat(OptionFormat.Seconds); PassCooldown = FloatOptionItem.Create(Id + 11, "AgitaterPassCooldown", new(0f, 5f, 0.25f), 1f, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Agitater]) .SetValueFormat(OptionFormat.Seconds); - BombExplodeCooldown = FloatOptionItem.Create(Id + 12, "BombExplodeCooldown", new(1f, 10f, 1f), 10f, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Agitater]) + BombExplodeCooldown = FloatOptionItem.Create(Id + 12, "BombExplodeCooldown", new(1f, 60f, 1f), 10f, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Agitater]) .SetValueFormat(OptionFormat.Seconds); AgitaterCanGetBombed = BooleanOptionItem.Create(Id + 13, "AgitaterCanGetBombed", false, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Agitater]); AgitaterAutoReportBait = BooleanOptionItem.Create(Id + 14, "AgitaterAutoReportBait", false, TabGroup.NeutralRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Agitater]); diff --git a/Roles/Neutral/CursedSoul.cs b/Roles/Neutral/CursedSoul.cs index d154fc9c0..8e9844ba6 100644 --- a/Roles/Neutral/CursedSoul.cs +++ b/Roles/Neutral/CursedSoul.cs @@ -16,6 +16,7 @@ public static class CursedSoul public static OptionItem CurseCooldownIncrese; public static OptionItem CurseMax; public static OptionItem KnowTargetRole; + public static OptionItem SoullessWinsWithCS; public static OptionItem CanCurseNeutral; private static int CurseLimit; @@ -29,6 +30,7 @@ public static class CursedSoul CurseMax = IntegerOptionItem.Create(Id + 12, "CursedSoulCurseMax", new(1, 15, 1), 3, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.CursedSoul]) .SetValueFormat(OptionFormat.Times); KnowTargetRole = BooleanOptionItem.Create(Id + 13, "CursedSoulKnowTargetRole", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.CursedSoul]); + SoullessWinsWithCS = BooleanOptionItem.Create(Id + 14, "SoullessWinsWithCS", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.CursedSoul]); CanCurseNeutral = BooleanOptionItem.Create(Id + 16, "CursedSoulCanCurseNeutral", false, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.CursedSoul]); } public static void Init() diff --git a/TOHE.csproj b/TOHE.csproj index 2b27883d1..96b41091d 100644 --- a/TOHE.csproj +++ b/TOHE.csproj @@ -7,7 +7,7 @@ TOHE+ Gurge44 latest - E:\Program Files\AmongUs + D:\Epic Games\AmongUs true True diff --git a/main.cs b/main.cs index 634e6412e..263a5f145 100644 --- a/main.cs +++ b/main.cs @@ -185,6 +185,7 @@ public class Main : BasePlugin public static Dictionary RevolutionistLastTime = new(); public static Dictionary RevolutionistCountdown = new(); public static Dictionary PuppeteerList = new(); + public static Dictionary PuppeteerDelayList = new(); public static Dictionary TaglockedList = new(); public static Dictionary SpeedBoostTarget = new(); public static Dictionary MayorUsedButtonCount = new();