diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..f694b8276 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# CA2211: Non-constant fields should not be visible +dotnet_diagnostic.CA2211.severity = none diff --git a/GameMode/FFAManager.cs b/GameMode/FFAManager.cs index 9fca5f4c2..815735546 100644 --- a/GameMode/FFAManager.cs +++ b/GameMode/FFAManager.cs @@ -91,12 +91,6 @@ internal static class FFAManager foreach (var pc in Main.AllAlivePlayerControls) { - //PlayerHPMax.TryAdd(pc.PlayerId, KB_HPMax.GetFloat()); - //PlayerHP.TryAdd(pc.PlayerId, KB_HPMax.GetFloat()); - //PlayerHPReco.TryAdd(pc.PlayerId, KB_RecoverPerSecond.GetFloat()); - //PlayerATK.TryAdd(pc.PlayerId, KB_ATK.GetFloat()); - //PlayerDF.TryAdd(pc.PlayerId, 0f); - KBScore.TryAdd(pc.PlayerId, 0); } } @@ -339,9 +333,11 @@ internal static class FFAManager if (FFA_EnableRandomTwists.GetBool() && FFAdoTP) { - List changePositionPlayers = new(); + Logger.Info("Swap everyone with someone", "FFA"); + List changePositionPlayers = new(); var rd = IRandom.Instance; + foreach (var pc in Main.AllAlivePlayerControls) { if (changePositionPlayers.Contains(pc.PlayerId) || !pc.IsAlive() || pc.onLadder || pc.inVent) continue; @@ -372,29 +368,37 @@ internal static class FFAManager if (Main.NormalOptions.MapId == 4) return; + bool sync = false; + if (FFADecreasedSpeedList.TryGetValue(__instance.PlayerId, out var dstime) && dstime + FFA_ModifiedSpeedDuration.GetInt() < Utils.GetTimeStamp()) { + Logger.Info(__instance.GetRealName() + "'s decreased speed expired", "FFA"); FFADecreasedSpeedList.Remove(__instance.PlayerId); Main.AllPlayerSpeed[__instance.PlayerId] = originalSpeed[__instance.PlayerId]; originalSpeed.Remove(__instance.PlayerId); - __instance.SyncSettings(); + sync = true; } if (FFAIncreasedSpeedList.TryGetValue(__instance.PlayerId, out var istime) && istime + FFA_ModifiedSpeedDuration.GetInt() < Utils.GetTimeStamp()) { + Logger.Info(__instance.GetRealName() + "'s increased speed expired", "FFA"); FFAIncreasedSpeedList.Remove(__instance.PlayerId); Main.AllPlayerSpeed[__instance.PlayerId] = originalSpeed[__instance.PlayerId]; originalSpeed.Remove(__instance.PlayerId); - __instance.SyncSettings(); + sync = true; } if (FFALowerVisionList.TryGetValue(__instance.PlayerId, out var lvtime) && lvtime + FFA_ModifiedSpeedDuration.GetInt() < Utils.GetTimeStamp()) { + Logger.Info(__instance.GetRealName() + "'s lower vision effect expired", "FFA"); FFALowerVisionList.Remove(__instance.PlayerId); - __instance.SyncSettings(); + sync = true; } if (FFAShieldedList.TryGetValue(__instance.PlayerId, out var stime) && stime + FFA_ShieldDuration.GetInt() < Utils.GetTimeStamp()) { + Logger.Info(__instance.GetRealName() + "'s shield expired", "FFA"); FFAShieldedList.Remove(__instance.PlayerId); } + + if (sync) __instance.SyncSettings(); } } } diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index d1785dcb0..0165f1058 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -82,6 +82,7 @@ internal static class CustomRolesHelper CustomRoles.Express => CustomRoles.Crewmate, CustomRoles.NiceEraser => CustomRoles.Crewmate, CustomRoles.TaskManager => CustomRoles.Crewmate, + CustomRoles.CameraMan => Options.UsePets.GetBool() ? CustomRoles.Crewmate : CustomRoles.Engineer, CustomRoles.Spy => CustomRoles.Crewmate, CustomRoles.Ricochet => CustomRoles.Crewmate, CustomRoles.Tether => CustomRoles.Engineer, @@ -146,6 +147,7 @@ internal static class CustomRolesHelper CustomRoles.Lookout => CustomRoles.Crewmate, CustomRoles.Retributionist => CustomRoles.Crewmate, CustomRoles.Guardian => CustomRoles.Crewmate, + CustomRoles.Enigma => CustomRoles.Crewmate, CustomRoles.Addict => CustomRoles.Engineer, CustomRoles.Alchemist => CustomRoles.Engineer, CustomRoles.Chameleon => CustomRoles.Engineer, @@ -175,6 +177,7 @@ internal static class CustomRolesHelper CustomRoles.Mediumshiper => CustomRoles.CrewmateTOHE, CustomRoles.Bodyguard => CustomRoles.CrewmateTOHE, CustomRoles.ParityCop => CustomRoles.CrewmateTOHE, + CustomRoles.Enigma => CustomRoles.CrewmateTOHE, CustomRoles.Grenadier => CustomRoles.EngineerTOHE, CustomRoles.SecurityGuard => CustomRoles.EngineerTOHE, CustomRoles.Lighter => CustomRoles.EngineerTOHE, @@ -193,6 +196,7 @@ internal static class CustomRolesHelper CustomRoles.Express => CustomRoles.CrewmateTOHE, CustomRoles.NiceEraser => CustomRoles.CrewmateTOHE, CustomRoles.TaskManager => CustomRoles.CrewmateTOHE, + CustomRoles.CameraMan => CustomRoles.EngineerTOHE, CustomRoles.Spy => CustomRoles.CrewmateTOHE, CustomRoles.Ricochet => CustomRoles.CrewmateTOHE, CustomRoles.Aid => CustomRoles.CrewmateTOHE, diff --git a/Modules/CustomSounds.cs b/Modules/CustomSounds.cs index 6ce4708d8..1a04ab7e0 100644 --- a/Modules/CustomSounds.cs +++ b/Modules/CustomSounds.cs @@ -56,8 +56,12 @@ public static class CustomSoundsManager Logger.Msg($"播放声音:{sound}", "CustomSounds"); } +#pragma warning disable CA2101 // Specify marshaling for P/Invoke string arguments [DllImport("winmm.dll")] +#pragma warning restore CA2101 // Specify marshaling for P/Invoke string arguments +#pragma warning disable CA1401 // P/Invokes should not be visible public static extern bool PlaySound(string Filename, int Mod, int Flags); +#pragma warning restore CA1401 // P/Invokes should not be visible public static void StartPlay(string path) => PlaySound(@$"{path}", 0, 1); //第3个形参,把1换为9,连续播放 } diff --git a/Modules/EAC.cs b/Modules/EAC.cs index 1389c529c..f4544add2 100644 --- a/Modules/EAC.cs +++ b/Modules/EAC.cs @@ -38,16 +38,16 @@ internal class EAC string name = sr.ReadString(); if (sr.BytesRemaining > 0 && sr.ReadBoolean()) return false; if ( - ((name.Contains("")) && name.Contains("?") && !name.Contains("color")) || + ((name.Contains("")) && name.Contains('?') && !name.Contains("color")) || name.Length > 160 || name.Count(f => f.Equals("\"\\n\"")) > 3 || name.Count(f => f.Equals("\n")) > 3 || name.Count(f => f.Equals("\r")) > 3 || - name.Contains("░") || - name.Contains("▄") || - name.Contains("█") || - name.Contains("▌") || - name.Contains("▒") || + name.Contains('░') || + name.Contains('▄') || + name.Contains('█') || + name.Contains('▌') || + name.Contains('▒') || name.Contains("习近平") ) { @@ -71,11 +71,11 @@ internal class EAC var text = sr.ReadString(); if (text.StartsWith("/")) return false; if ( - text.Contains("░") || - text.Contains("▄") || - text.Contains("█") || - text.Contains("▌") || - text.Contains("▒") || + text.Contains('░') || + text.Contains('▄') || + text.Contains('█') || + text.Contains('▌') || + text.Contains('▒') || text.Contains("习近平") ) { diff --git a/Modules/ErrorText.cs b/Modules/ErrorText.cs index 8c399433d..d34d382bd 100644 --- a/Modules/ErrorText.cs +++ b/Modules/ErrorText.cs @@ -15,19 +15,19 @@ public class ErrorText : MonoBehaviour return _instance; } } - private static ErrorText _instance; - private void Awake() - { - if (_instance != null) - { - Destroy(gameObject); - } - else - { - _instance = this; - DontDestroyOnLoad(this); - } - } + private static readonly ErrorText _instance; + //private void Awake() + //{ + // if (_instance != null) + // { + // Destroy(gameObject); + // } + // else + // { + // _instance = this; + // DontDestroyOnLoad(this); + // } + //} #endregion public static void Create(TMPro.TextMeshPro baseText) { diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs index 712dd1083..b8d2a20d0 100644 --- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs +++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs @@ -294,6 +294,10 @@ public class PlayerGameOptionsSender : GameOptionsSender AURoleOptions.ShapeshifterCooldown = Hitman.ShapeshiftCooldown.GetFloat(); AURoleOptions.ShapeshifterDuration = 1f; break; + case CustomRoles.CameraMan: + AURoleOptions.EngineerCooldown = CameraMan.VentCooldown.GetFloat(); + AURoleOptions.EngineerInVentMaxTime = 1f; + break; case CustomRoles.Mafia: AURoleOptions.ShapeshifterCooldown = Options.MafiaShapeshiftCD.GetFloat(); AURoleOptions.ShapeshifterDuration = Options.MafiaShapeshiftDur.GetFloat(); diff --git a/Modules/GameState.cs b/Modules/GameState.cs index 8043c411d..a8f65ea83 100644 --- a/Modules/GameState.cs +++ b/Modules/GameState.cs @@ -12,12 +12,14 @@ namespace TOHE; public class PlayerState { - byte PlayerId; + readonly byte PlayerId; public CustomRoles MainRole; public List SubRoles; public CountTypes countTypes; public bool IsDead { get; set; } +#pragma warning disable IDE1006 // Naming Styles public DeathReason deathReason { get; set; } +#pragma warning restore IDE1006 // Naming Styles public TaskState taskState; public bool IsBlackOut { get; set; } public (DateTime, byte) RealKiller; @@ -486,6 +488,9 @@ public class TaskState if (!player.IsModClient()) NiceHacker.UseLimit[player.PlayerId] += NiceHacker.NiceHackerAbilityUseGainWithEachTaskCompleted.GetFloat(); else NiceHacker.UseLimitSeconds[player.PlayerId] += NiceHacker.NiceHackerAbilityUseGainWithEachTaskCompleted.GetInt() * NiceHacker.ModdedClientAbilityUseSecondsMultiplier.GetInt(); break; + case CustomRoles.CameraMan: + CameraMan.UseLimit[player.PlayerId] += CameraMan.CameraManAbilityUseGainWithEachTaskCompleted.GetFloat(); + break; } } if (player.Is(CustomRoles.Express) && player.IsAlive()) @@ -596,8 +601,10 @@ public class PlayerVersion public readonly Version version; public readonly string tag; public readonly string forkId; +#pragma warning disable CA1041 // Provide ObsoleteAttribute message [Obsolete] public PlayerVersion(string ver, string tag_str) : this(Version.Parse(ver), tag_str, string.Empty) { } [Obsolete] public PlayerVersion(Version ver, string tag_str) : this(ver, tag_str, string.Empty) { } +#pragma warning restore CA1041 // Provide ObsoleteAttribute message public PlayerVersion(string ver, string tag_str, string forkId) : this(Version.Parse(ver), tag_str, forkId) { } public PlayerVersion(Version ver, string tag_str, string forkId) { @@ -634,9 +641,12 @@ public static class GameStates public static class MeetingStates { public static DeadBody[] DeadBodies = null; - public static GameData.PlayerInfo ReportTarget = null; + private static GameData.PlayerInfo reportTarget = null; public static bool IsEmergencyMeeting => ReportTarget == null; public static bool IsExistDeadBody => DeadBodies.Length > 0; + + public static GameData.PlayerInfo ReportTarget { get => reportTarget; set => reportTarget = value; } + public static bool MeetingCalled = false; public static bool FirstMeeting = true; } \ No newline at end of file diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 7262e02c2..2f445b854 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -1322,6 +1322,8 @@ public static class Options .SetParent(CustomRoleSpawnChances[CustomRoles.Demolitionist]); RoleLoadingText = "Crewmate roles\nTask Manager"; SetupSingleRoleOptions(5575, TabGroup.CrewmateRoles, CustomRoles.TaskManager, 1); + RoleLoadingText = "Crewmate roles\nCamera Man"; + CameraMan.SetupCustomOption(); RoleLoadingText = "Crewmate roles\nHacker"; NiceHacker.SetupCustomOption(); RoleLoadingText = "Crewmate roles\nDoormaster"; @@ -1334,6 +1336,8 @@ public static class Options Tether.SetupCustomOption(); RoleLoadingText = "Crewmate roles\nSpy"; Spy.SetupCustomOption(); + RoleLoadingText = "Crewmate roles\nEnigma"; + Enigma.SetupCustomOption(); RoleLoadingText = "Crewmate roles\nExpress"; SetupRoleOptions(5585, TabGroup.CrewmateRoles, CustomRoles.Express); ExpressSpeed = FloatOptionItem.Create(5587, "ExpressSpeed", new(0.25f, 5f, 0.25f), 1.5f, TabGroup.CrewmateRoles, false) diff --git a/Modules/RPC.cs b/Modules/RPC.cs index 4979cdd03..af89fe230 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -861,6 +861,9 @@ internal static class RPC case CustomRoles.Executioner: Executioner.Add(targetId); break; + case CustomRoles.Enigma: + Enigma.Add(targetId); + break; case CustomRoles.Farseer: Farseer.Add(targetId); break; @@ -1162,6 +1165,9 @@ internal static class RPC case CustomRoles.Dazzler: Dazzler.Add(targetId); break; + case CustomRoles.CameraMan: + CameraMan.Add(targetId); + break; case CustomRoles.Hitman: Hitman.Add(targetId); break; @@ -1333,7 +1339,7 @@ internal static class RPC [HarmonyPatch(typeof(InnerNet.InnerNetClient), nameof(InnerNet.InnerNetClient.StartRpc))] internal class StartRpcPatch { - public static void Prefix(InnerNet.InnerNetClient __instance, [HarmonyArgument(0)] uint targetNetId, [HarmonyArgument(1)] byte callId) + public static void Prefix(/*InnerNet.InnerNetClient __instance,*/ [HarmonyArgument(0)] uint targetNetId, [HarmonyArgument(1)] byte callId) { RPC.SendRpcLogger(targetNetId, callId); } @@ -1341,7 +1347,7 @@ internal class StartRpcPatch [HarmonyPatch(typeof(InnerNet.InnerNetClient), nameof(InnerNet.InnerNetClient.StartRpcImmediately))] internal class StartRpcImmediatelyPatch { - public static void Prefix(InnerNet.InnerNetClient __instance, [HarmonyArgument(0)] uint targetNetId, [HarmonyArgument(1)] byte callId, [HarmonyArgument(3)] int targetClientId = -1) + public static void Prefix(/*InnerNet.InnerNetClient __instance,*/ [HarmonyArgument(0)] uint targetNetId, [HarmonyArgument(1)] byte callId, [HarmonyArgument(3)] int targetClientId = -1) { RPC.SendRpcLogger(targetNetId, callId, targetClientId); } diff --git a/Modules/SpamManager.cs b/Modules/SpamManager.cs index a9363afa1..4efb9b567 100644 --- a/Modules/SpamManager.cs +++ b/Modules/SpamManager.cs @@ -245,36 +245,36 @@ public static class SpamManager if (text.Contains("s t a r t")) return true; if (text.Contains("begin")) return true; - if (text.Contains("了")) return false; - if (text.Contains("没")) return false; - if (text.Contains("吗")) return false; - if (text.Contains("哈")) return false; - if (text.Contains("还")) return false; - if (text.Contains("现")) return false; - if (text.Contains("不")) return false; - if (text.Contains("可")) return false; - if (text.Contains("刚")) return false; - if (text.Contains("的")) return false; - if (text.Contains("打")) return false; - if (text.Contains("门")) return false; - if (text.Contains("关")) return false; - if (text.Contains("怎")) return false; - if (text.Contains("要")) return false; - if (text.Contains("摆")) return false; - if (text.Contains("啦")) return false; - if (text.Contains("咯")) return false; - if (text.Contains("嘞")) return false; - if (text.Contains("勒")) return false; - if (text.Contains("心")) return false; - if (text.Contains("呢")) return false; - if (text.Contains("门")) return false; - if (text.Contains("总")) return false; - if (text.Contains("哥")) return false; - if (text.Contains("姐")) return false; - if (text.Contains("《")) return false; - if (text.Contains("?")) return false; - if (text.Contains("?")) return false; + if (text.Contains('了')) return false; + if (text.Contains('没')) return false; + if (text.Contains('吗')) return false; + if (text.Contains('哈')) return false; + if (text.Contains('还')) return false; + if (text.Contains('现')) return false; + if (text.Contains('不')) return false; + if (text.Contains('可')) return false; + if (text.Contains('刚')) return false; + if (text.Contains('的')) return false; + if (text.Contains('打')) return false; + if (text.Contains('门')) return false; + if (text.Contains('关')) return false; + if (text.Contains('怎')) return false; + if (text.Contains('要')) return false; + if (text.Contains('摆')) return false; + if (text.Contains('啦')) return false; + if (text.Contains('咯')) return false; + if (text.Contains('嘞')) return false; + if (text.Contains('勒')) return false; + if (text.Contains('心')) return false; + if (text.Contains('呢')) return false; + if (text.Contains('门')) return false; + if (text.Contains('总')) return false; + if (text.Contains('哥')) return false; + if (text.Contains('姐')) return false; + if (text.Contains('《')) return false; + if (text.Contains('?')) return false; + if (text.Contains('?')) return false; - return text.Contains("开") || text.Contains("kai"); + return text.Contains('开') || text.Contains("kai"); } } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 8cc9be3e2..fb51ff316 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -313,7 +313,7 @@ public static class Utils public static Color GetRoleColor(CustomRoles role) { if (!Main.roleColors.TryGetValue(role, out var hexColor)) hexColor = "#ffffff"; - ColorUtility.TryParseHtmlString(hexColor, out Color c); + _ = ColorUtility.TryParseHtmlString(hexColor, out Color c); return c; } public static string GetRoleColorCode(CustomRoles role) @@ -611,547 +611,560 @@ public static class Utils if (!Main.playerVersion.ContainsKey(0)) return string.Empty; //ホストがMODを入れていなければ未記入を返す var ProgressText = new StringBuilder(); var role = Main.PlayerStates[playerId].MainRole; - switch (role) + try { - case CustomRoles.Arsonist: - var doused = GetDousedPlayerCount(playerId); - if (!Options.ArsonistCanIgniteAnytime.GetBool()) ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Arsonist).ShadeColor(0.25f), $"- {doused.Item1}/{doused.Item2}")); - else ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Arsonist).ShadeColor(0.25f), $"- {doused.Item1}/{Options.ArsonistMaxPlayersToIgnite.GetInt()}")); - break; - case CustomRoles.Sheriff: - if (Sheriff.ShowShotLimit.GetBool()) ProgressText.Append(Sheriff.GetShotLimit(playerId)); - break; - case CustomRoles.Alchemist: - ProgressText.Append(Alchemist.GetProgressText(playerId)); - if (Options.UsePets.GetBool() && Main.AlchemistCD.TryGetValue(playerId, out var time) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Alchemist.VentCooldown.GetInt() - (GetTimeStamp() - time) + 1)); - break; - case CustomRoles.Bandit: - ProgressText.Append(Bandit.GetStealLimit(playerId)); - break; - case CustomRoles.Cleanser: - ProgressText.Append(Cleanser.GetProgressText(playerId)); - break; - case CustomRoles.SerialKiller: - if (SerialKiller.SuicideTimer.ContainsKey(playerId)) - { - int SKTime = SerialKiller.TimeLimit.GetInt() - (int)SerialKiller.SuicideTimer[playerId]; - Color SKColor = SKTime < 10 ? SKTime % 2 == 1 ? Color.yellow : Color.red : Color.white; - if (SKTime <= 20) ProgressText.Append(ColorString(SKColor, $"- {SKTime}s")); - } - break; - case CustomRoles.BountyHunter: - if (BountyHunter.ChangeTimer.ContainsKey(playerId)) - { - int BHTime = (int)(BountyHunter.TargetChangeTime - (float)BountyHunter.ChangeTimer[playerId]); - if (BHTime <= 15) ProgressText.Append(ColorString(Color.white, $"- SWAP: {BHTime}s")); - } - break; - case CustomRoles.Camouflager: - Color TextColorCamo; - if (Camouflager.CamoLimit[playerId] < 1) TextColorCamo = Color.grey; - else TextColorCamo = Color.white; - ProgressText.Append(ColorString(TextColorCamo, $"- {Math.Round(Camouflager.CamoLimit[playerId], 1)}")); - break; - case CustomRoles.Councillor: - Color TextColorCoun; - if (Councillor.MurderLimit[playerId] < 1) TextColorCoun = Color.grey; - else TextColorCoun = Color.white; - ProgressText.Append(ColorString(TextColorCoun, $"- {Math.Round(Councillor.MurderLimit[playerId], 1)}")); - break; - case CustomRoles.Dazzler: - Color TextColorDazzler; - if (Dazzler.DazzleLimit[playerId] < 1) TextColorDazzler = Color.grey; - else TextColorDazzler = Color.white; - ProgressText.Append(ColorString(TextColorDazzler, $"- {Math.Round(Dazzler.DazzleLimit[playerId], 1)}")); - break; - case CustomRoles.Disperser: - Color TextColorDisperser; - if (Disperser.DisperserLimit[playerId] < 1) TextColorDisperser = Color.grey; - else TextColorDisperser = Color.white; - ProgressText.Append(ColorString(TextColorDisperser, $"- {Math.Round(Disperser.DisperserLimit[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.DisperserCD.TryGetValue(playerId, out var time11) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Disperser.DisperserShapeshiftCooldown.GetInt() - (GetTimeStamp() - time11) + 1)); - break; - case CustomRoles.Hangman: - Color TextColorHangman; - if (Hangman.HangLimit[playerId] < 1) TextColorHangman = Color.grey; - else TextColorHangman = Color.white; - ProgressText.Append(ColorString(TextColorHangman, $"- {Math.Round(Hangman.HangLimit[playerId], 1)}")); - break; - case CustomRoles.Twister: - Color TextColorTwister; - if (Twister.TwistLimit[playerId] < 1) TextColorTwister = Color.grey; - else TextColorTwister = Color.white; - ProgressText.Append(ColorString(TextColorTwister, $"- {Math.Round(Twister.TwistLimit[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.TwisterCD.TryGetValue(playerId, out var time12) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Twister.ShapeshiftCooldown.GetInt() - (GetTimeStamp() - time12) + 1)); - break; - case CustomRoles.EvilDiviner: - Color TextColorED; - if (EvilDiviner.DivinationCount[playerId] < 1) TextColorED = Color.grey; - else TextColorED = Color.white; - ProgressText.Append(ColorString(TextColorED, $"- {Math.Round(EvilDiviner.DivinationCount[playerId], 1)}")); - break; - case CustomRoles.Swooper: - Color TextColorSwooper; - if (Swooper.SwoopLimit[playerId] < 1) TextColorSwooper = Color.grey; - else TextColorSwooper = Color.white; - ProgressText.Append(ColorString(TextColorSwooper, $"- {Math.Round(Swooper.SwoopLimit[playerId], 1)}")); - break; - case CustomRoles.Jailor: - ProgressText.Append(Jailor.GetProgressText(playerId)); - break; - case CustomRoles.NiceSwapper: - ProgressText.Append(NiceSwapper.GetNiceSwappermax(playerId)); - break; - case CustomRoles.Veteran: - var taskState2 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor2; - var TaskCompleteColor2 = Color.green; - var NonCompleteColor2 = Color.yellow; - var NormalColor2 = taskState2.IsTaskFinished ? TaskCompleteColor2 : NonCompleteColor2; - TextColor2 = comms ? Color.gray : NormalColor2; - string Completed2 = comms ? "?" : $"{taskState2.CompletedTasksCount}"; - Color TextColor21; - if (Main.VeteranNumOfUsed[playerId] < 1) TextColor21 = Color.red; - else if (Main.VeteranInProtect.ContainsKey(playerId)) TextColor21 = Color.green; - else TextColor21 = Color.white; - ProgressText.Append(ColorString(TextColor2, $"- {Completed2}/{taskState2.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor21, $" - {Math.Round(Main.VeteranNumOfUsed[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.VeteranCD.TryGetValue(playerId, out var time2) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.VeteranSkillCooldown.GetInt() + Options.VeteranSkillDuration.GetInt() - (GetTimeStamp() - time2) + 1)); - break; - case CustomRoles.Grenadier: - var taskState3 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor3; - var TaskCompleteColor3 = Color.green; - var NonCompleteColor3 = Color.yellow; - var NormalColor3 = taskState3.IsTaskFinished ? TaskCompleteColor3 : NonCompleteColor3; - TextColor3 = comms ? Color.gray : NormalColor3; - string Completed3 = comms ? "?" : $"{taskState3.CompletedTasksCount}"; - Color TextColor31; - if (Main.GrenadierNumOfUsed[playerId] < 1) TextColor31 = Color.red; - else if (Main.GrenadierBlinding.ContainsKey(playerId)) TextColor31 = Color.green; - else TextColor31 = Color.white; - ProgressText.Append(ColorString(TextColor3, $"- {Completed3}/{taskState3.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor31, $" - {Math.Round(Main.GrenadierNumOfUsed[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.GrenadierCD.TryGetValue(playerId, out var time3) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.GrenadierSkillCooldown.GetInt() + Options.GrenadierSkillDuration.GetInt() - (GetTimeStamp() - time3) + 1)); - break; - case CustomRoles.Divinator: - var taskState4 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor4; - var TaskCompleteColor4 = Color.green; - var NonCompleteColor4 = Color.yellow; - var NormalColor4 = taskState4.IsTaskFinished ? TaskCompleteColor4 : NonCompleteColor4; - TextColor4 = comms ? Color.gray : NormalColor4; - string Completed4 = comms ? "?" : $"{taskState4.CompletedTasksCount}"; - Color TextColor41; - if (Divinator.CheckLimit[playerId] < 1) TextColor41 = Color.red; - else TextColor41 = Color.white; - ProgressText.Append(ColorString(TextColor4, $"- {Completed4}/{taskState4.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor41, $" - {Math.Round(Divinator.CheckLimit[playerId])}")); - break; - case CustomRoles.DovesOfNeace: - var taskState5 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor5; - var TaskCompleteColor5 = Color.green; - var NonCompleteColor5 = Color.yellow; - var NormalColor5 = taskState5.IsTaskFinished ? TaskCompleteColor5 : NonCompleteColor5; - TextColor5 = comms ? Color.gray : NormalColor5; - string Completed5 = comms ? "?" : $"{taskState5.CompletedTasksCount}"; - Color TextColor51; - if (Main.DovesOfNeaceNumOfUsed[playerId] < 1) TextColor51 = Color.red; - else TextColor51 = Color.white; - ProgressText.Append(ColorString(TextColor5, $"- {Completed5}/{taskState5.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor51, $" - {Math.Round(Main.DovesOfNeaceNumOfUsed[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.DovesOfNeaceCD.TryGetValue(playerId, out var time4) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.DovesOfNeaceCooldown.GetInt() - (GetTimeStamp() - time4) + 1)); - break; - case CustomRoles.TimeMaster: - var taskState6 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor6; - var TaskCompleteColor6 = Color.green; - var NonCompleteColor6 = Color.yellow; - var NormalColor6 = taskState6.IsTaskFinished ? TaskCompleteColor6 : NonCompleteColor6; - TextColor6 = comms ? Color.gray : NormalColor6; - string Completed6 = comms ? "?" : $"{taskState6.CompletedTasksCount}"; - Color TextColor61; - if (Main.TimeMasterNumOfUsed[playerId] < 1) TextColor61 = Color.red; - else if (Main.TimeMasterInProtect.ContainsKey(playerId)) TextColor61 = Color.green; - else TextColor61 = Color.white; - ProgressText.Append(ColorString(TextColor6, $"- {Completed6}/{taskState6.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor61, $" - {Math.Round(Main.TimeMasterNumOfUsed[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.TimeMasterCD.TryGetValue(playerId, out var time5) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.TimeMasterSkillCooldown.GetInt() + Options.TimeMasterSkillDuration.GetInt() - (GetTimeStamp() - time5) + 1)); - break; - case CustomRoles.Mediumshiper: - var taskState7 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor7; - var TaskCompleteColor7 = Color.green; - var NonCompleteColor7 = Color.yellow; - var NormalColor7 = taskState7.IsTaskFinished ? TaskCompleteColor7 : NonCompleteColor7; - TextColor7 = comms ? Color.gray : NormalColor7; - string Completed7 = comms ? "?" : $"{taskState7.CompletedTasksCount}"; - Color TextColor71; - if (Mediumshiper.ContactLimit[playerId] < 1) TextColor71 = Color.red; - else TextColor71 = Color.white; - ProgressText.Append(ColorString(TextColor7, $"- {Completed7}/{taskState7.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor71, $" - {Math.Round(Mediumshiper.ContactLimit[playerId], 1)}")); - break; - case CustomRoles.ParityCop: - var taskState8 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor8; - var TaskCompleteColor8 = Color.green; - var NonCompleteColor8 = Color.yellow; - var NormalColor8 = taskState8.IsTaskFinished ? TaskCompleteColor8 : NonCompleteColor8; - TextColor8 = comms ? Color.gray : NormalColor8; - string Completed8 = comms ? "?" : $"{taskState8.CompletedTasksCount}"; - Color TextColor81; - if (ParityCop.MaxCheckLimit[playerId] < 1) TextColor81 = Color.red; - else TextColor81 = Color.white; - ProgressText.Append(ColorString(TextColor8, $"- {Completed8}/{taskState8.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor81, $" - {Math.Round(ParityCop.MaxCheckLimit[playerId], 1)}")); - break; - case CustomRoles.Oracle: - var taskState9 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor9; - var TaskCompleteColor9 = Color.green; - var NonCompleteColor9 = Color.yellow; - var NormalColor9 = taskState9.IsTaskFinished ? TaskCompleteColor9 : NonCompleteColor9; - TextColor9 = comms ? Color.gray : NormalColor9; - string Completed9 = comms ? "?" : $"{taskState9.CompletedTasksCount}"; - Color TextColor91; - if (Oracle.CheckLimit[playerId] < 1) TextColor91 = Color.red; - else TextColor91 = Color.white; - ProgressText.Append(ColorString(TextColor9, $"- {Completed9}/{taskState9.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor91, $" - {Math.Round(Oracle.CheckLimit[playerId], 1)}")); - break; - case CustomRoles.SabotageMaster: - var taskState10 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor10; - var TaskCompleteColor10 = Color.green; - var NonCompleteColor10 = Color.yellow; - var NormalColor10 = taskState10.IsTaskFinished ? TaskCompleteColor10 : NonCompleteColor10; - TextColor10 = comms ? Color.gray : NormalColor10; - string Completed10 = comms ? "?" : $"{taskState10.CompletedTasksCount}"; - Color TextColor101; - if (SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount > 1) TextColor101 = Color.red; - else TextColor101 = Color.white; - ProgressText.Append(ColorString(TextColor10, $"- {Completed10}/{taskState10.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor101, $" - {Math.Round(SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount, 1)}")); - break; - case CustomRoles.Tracker: - var taskState11 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor11; - var TaskCompleteColor11 = Color.green; - var NonCompleteColor11 = Color.yellow; - var NormalColor11 = taskState11.IsTaskFinished ? TaskCompleteColor11 : NonCompleteColor11; - TextColor11 = comms ? Color.gray : NormalColor11; - string Completed11 = comms ? "?" : $"{taskState11.CompletedTasksCount}"; - Color TextColor111; - if (Tracker.TrackLimit[playerId] < 1) TextColor111 = Color.red; - else TextColor111 = Color.white; - ProgressText.Append(ColorString(TextColor11, $"- {Completed11}/{taskState11.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor111, $" - {Math.Round(Tracker.TrackLimit[playerId], 1)}")); - break; - case CustomRoles.Bloodhound: - var taskState12 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor12; - var TaskCompleteColor12 = Color.green; - var NonCompleteColor12 = Color.yellow; - var NormalColor12 = taskState12.IsTaskFinished ? TaskCompleteColor12 : NonCompleteColor12; - TextColor12 = comms ? Color.gray : NormalColor12; - string Completed12 = comms ? "?" : $"{taskState12.CompletedTasksCount}"; - Color TextColor121; - if (Bloodhound.UseLimit[playerId] < 1) TextColor121 = Color.red; - else TextColor121 = Color.white; - ProgressText.Append(ColorString(TextColor12, $"- {Completed12}/{taskState12.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor121, $" - {Math.Round(Bloodhound.UseLimit[playerId], 1)}")); - break; - case CustomRoles.Chameleon: - var taskState13 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor13; - var TaskCompleteColor13 = Color.green; - var NonCompleteColor13 = Color.yellow; - var NormalColor13 = taskState13.IsTaskFinished ? TaskCompleteColor13 : NonCompleteColor13; - TextColor13 = comms ? Color.gray : NormalColor13; - string Completed13 = comms ? "?" : $"{taskState13.CompletedTasksCount}"; - Color TextColor131; - if (Chameleon.UseLimit[playerId] < 1) TextColor131 = Color.red; - else if (Chameleon.IsInvis(playerId)) TextColor131 = Color.green; - else TextColor131 = Color.white; - ProgressText.Append(ColorString(TextColor13, $"- {Completed13}/{taskState13.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor131, $" - {Math.Round(Chameleon.UseLimit[playerId], 1)}")); - break; - case CustomRoles.Lighter: - var taskState14 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor14; - var TaskCompleteColor14 = Color.green; - var NonCompleteColor14 = Color.yellow; - var NormalColor14 = taskState14.IsTaskFinished ? TaskCompleteColor14 : NonCompleteColor14; - TextColor14 = comms ? Color.gray : NormalColor14; - string Completed14 = comms ? "?" : $"{taskState14.CompletedTasksCount}"; - Color TextColor141; - if (Main.LighterNumOfUsed[playerId] < 1) TextColor141 = Color.red; - else if (Main.Lighter.ContainsKey(playerId)) TextColor141 = Color.green; - else TextColor141 = Color.white; - ProgressText.Append(ColorString(TextColor14, $"- {Completed14}/{taskState14.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor141, $" - {Math.Round(Main.LighterNumOfUsed[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.LighterCD.TryGetValue(playerId, out var time6) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.LighterSkillCooldown.GetInt() + Options.LighterSkillDuration.GetInt() - (GetTimeStamp() - time6) + 1)); - break; - case CustomRoles.Ventguard: - var taskState15 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor15; - var TaskCompleteColor15 = Color.green; - var NonCompleteColor15 = Color.yellow; - var NormalColor15 = taskState15.IsTaskFinished ? TaskCompleteColor15 : NonCompleteColor15; - TextColor15 = comms ? Color.gray : NormalColor15; - string Completed15 = comms ? "?" : $"{taskState15.CompletedTasksCount}"; - Color TextColor151; - if (Main.VentguardNumberOfAbilityUses < 1) TextColor151 = Color.red; - else TextColor151 = Color.white; - ProgressText.Append(ColorString(TextColor15, $"- {Completed15}/{taskState15.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor151, $" - {Math.Round(Main.VentguardNumberOfAbilityUses, 1)}")); - break; - case CustomRoles.SecurityGuard: - var taskState16 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor16; - var TaskCompleteColor16 = Color.green; - var NonCompleteColor16 = Color.yellow; - var NormalColor16 = taskState16.IsTaskFinished ? TaskCompleteColor16 : NonCompleteColor16; - TextColor16 = comms ? Color.gray : NormalColor16; - string Completed16 = comms ? "?" : $"{taskState16.CompletedTasksCount}"; - Color TextColor161; - if (Main.SecurityGuardNumOfUsed[playerId] < 1) TextColor161 = Color.red; - else if (Main.BlockSabo.ContainsKey(playerId)) TextColor161 = Color.green; - else TextColor161 = Color.white; - ProgressText.Append(ColorString(TextColor16, $"- {Completed16}/{taskState16.AllTasksCount}")); - ProgressText.Append(ColorString(TextColor161, $" - {Math.Round(Main.SecurityGuardNumOfUsed[playerId], 1)}")); - if (Options.UsePets.GetBool() && Main.SecurityGuardCD.TryGetValue(playerId, out var time7) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.SecurityGuardSkillCooldown.GetInt() + Options.SecurityGuardSkillDuration.GetInt() - (GetTimeStamp() - time7) + 1)); - break; - //case CustomRoles.Pirate: - // ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Pirate).ShadeColor(0.25f), $"({Pirate.NumWin}/{Pirate.SuccessfulDuelsToWin.GetInt()})")); - // break; - case CustomRoles.Crusader: - ProgressText.Append(Crusader.GetSkillLimit(playerId)); - break; - case CustomRoles.TaskManager: - var taskState1 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor1; - var TaskCompleteColor1 = Color.green; - var NonCompleteColor1 = Color.yellow; - var NormalColor1 = taskState1.IsTaskFinished ? TaskCompleteColor1 : NonCompleteColor1; - TextColor1 = comms ? Color.gray : NormalColor1; - string Completed1 = comms ? "?" : $"{taskState1.CompletedTasksCount}"; - string totalCompleted1 = comms ? "?" : $"{GameData.Instance.CompletedTasks}"; - ProgressText.Append(ColorString(TextColor1, $"- {Completed1}/{taskState1.AllTasksCount}")); - ProgressText.Append($" - {totalCompleted1}/{GameData.Instance.TotalTasks}"); - break; - case CustomRoles.NiceHacker: - ProgressText.Append(NiceHacker.GetProgressText(playerId, comms)); - if (Options.UsePets.GetBool() && Main.HackerCD.TryGetValue(playerId, out var time8) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), NiceHacker.AbilityCD.GetInt() - (GetTimeStamp() - time8) + 1)); - break; - case CustomRoles.RiftMaker: - ProgressText.Append(RiftMaker.GetProgressText()); - break; - case CustomRoles.Hitman: - ProgressText.Append(Hitman.GetProgressText()); - break; - case CustomRoles.Ricochet: - ProgressText.Append(Ricochet.GetProgressText(playerId, comms)); - break; - case CustomRoles.Doormaster: - ProgressText.Append(Doormaster.GetProgressText(playerId, comms)); - if (Options.UsePets.GetBool() && Main.DoormasterCD.TryGetValue(playerId, out var time9) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Doormaster.VentCooldown.GetInt() - (GetTimeStamp() - time9) + 1)); - break; - case CustomRoles.CopyCat: - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.CopyCat).ShadeColor(0.25f), $"({(CopyCat.MiscopyLimit.TryGetValue(playerId, out var count2) ? count2 : 0)})")); - break; - case CustomRoles.PlagueBearer: - var plagued = PlagueBearer.PlaguedPlayerCount(playerId); - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.PlagueBearer).ShadeColor(0.25f), $"- {plagued.Item1}/{plagued.Item2}")); - break; - case CustomRoles.Doomsayer: - var doomsayerguess = Doomsayer.GuessedPlayerCount(playerId); - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Doomsayer).ShadeColor(0.25f), $"- {doomsayerguess.Item1}/{doomsayerguess.Item2}")); - break; - case CustomRoles.Sniper: - ProgressText.Append(Sniper.GetBulletCount(playerId)); - if (Options.UsePets.GetBool() && Main.SniperCD.TryGetValue(playerId, out var time13) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.DefaultShapeshiftCooldown.GetInt() - (GetTimeStamp() - time13) + 1)); - break; - case CustomRoles.EvilTracker: - ProgressText.Append(EvilTracker.GetMarker(playerId)); - break; - case CustomRoles.TimeThief: - ProgressText.Append(TimeThief.GetProgressText(playerId)); - break; - case CustomRoles.Mario: - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Mario).ShadeColor(0.25f), $"- {(Main.MarioVentCount.TryGetValue(playerId, out var count) ? count : 0)}/{Options.MarioVentNumWin.GetInt()}")); - break; - case CustomRoles.Vulture: - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Vulture).ShadeColor(0.25f), $"- {(Vulture.BodyReportCount.TryGetValue(playerId, out var count1) ? count1 : 0)}/{Vulture.NumberOfReportsToWin.GetInt()}")); - break; - //case CustomRoles.Masochist: - // ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Masochist).ShadeColor(0.25f), $"- {(Main.MasochistKillMax.TryGetValue(playerId, out var count3) ? count3 : 0)}/{Options.MasochistKillMax.GetInt()}")); - // break; - case CustomRoles.QuickShooter: - ProgressText.Append(QuickShooter.GetShotLimit(playerId)); - if (Options.UsePets.GetBool() && Main.QuickShooterCD.TryGetValue(playerId, out var time14) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), QuickShooter.ShapeshiftCooldown.GetInt() - (GetTimeStamp() - time14) + 1)); - break; - case CustomRoles.SwordsMan: - ProgressText.Append(SwordsMan.GetKillLimit(playerId)); - break; - case CustomRoles.Pelican: - ProgressText.Append(Pelican.GetProgressText(playerId)); - break; - //case CustomRoles.Counterfeiter: - // ProgressText.Append(Counterfeiter.GetSeelLimit(playerId)); - // break; - case CustomRoles.Tether: - ProgressText.Append(Tether.GetProgressText(playerId, comms)); - if (Options.UsePets.GetBool() && Main.TetherCD.TryGetValue(playerId, out var time10) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Tether.VentCooldown.GetInt() - (GetTimeStamp() - time10) + 1)); - break; - case CustomRoles.Spy: - ProgressText.Append(Spy.GetProgressText(playerId, comms)); - break; - case CustomRoles.Aid: - ProgressText.Append(Aid.GetProgressText(playerId, comms)); - break; - case CustomRoles.Pursuer: - ProgressText.Append(Pursuer.GetSeelLimit(playerId)); - break; - case CustomRoles.Revolutionist: - var draw = GetDrawPlayerCount(playerId, out var _); - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Revolutionist).ShadeColor(0.25f), $"- {draw.Item1}/{draw.Item2}")); - break; - case CustomRoles.Gangster: - ProgressText.Append(Gangster.GetRecruitLimit(playerId)); - break; - case CustomRoles.Medic: - ProgressText.Append(Medic.GetSkillLimit(playerId)); - break; - case CustomRoles.CursedWolf: - int SpellCount = Main.CursedWolfSpellCount[playerId]; - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.CursedWolf), $"({SpellCount})")); - break; - case CustomRoles.Jinx: - int JinxSpellCount = Main.JinxSpellCount[playerId]; - ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Jinx), $"({JinxSpellCount})")); - break; - case CustomRoles.Collector: - ProgressText.Append(Collector.GetProgressText(playerId)); - break; - case CustomRoles.Eraser: - ProgressText.Append(Eraser.GetProgressText(playerId)); - break; - //case CustomRoles.NiceEraser: - // ProgressText.Append(NiceEraser.GetProgressText(playerId)); - // break; - case CustomRoles.Hacker: - ProgressText.Append(Hacker.GetHackLimit(playerId)); - break; - case CustomRoles.KB_Normal: - ProgressText.Append(SoloKombatManager.GetDisplayScore(playerId)); - break; - case CustomRoles.Bomber: - if (Options.UsePets.GetBool() && Main.BomberCD.TryGetValue(playerId, out var time15) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.BombCooldown.GetInt() - (GetTimeStamp() - time15) + 1)); - break; - case CustomRoles.Nuker: - if (Options.UsePets.GetBool() && Main.NukerCD.TryGetValue(playerId, out var time16) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.NukeCooldown.GetInt() - (GetTimeStamp() - time16) + 1)); - break; - case CustomRoles.Escapee: - if (Options.UsePets.GetBool() && Main.EscapeeCD.TryGetValue(playerId, out var time17) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.EscapeeSSCD.GetInt() - (GetTimeStamp() - time17) + 1)); - break; - case CustomRoles.Miner: - if (Options.UsePets.GetBool() && Main.MinerCD.TryGetValue(playerId, out var time18) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.MinerSSCD.GetInt() - (GetTimeStamp() - time18) + 1)); - break; - case CustomRoles.Assassin: - if (Options.UsePets.GetBool() && Main.AssassinCD.TryGetValue(playerId, out var time19) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Assassin.AssassinateCooldown.GetInt() - (GetTimeStamp() - time19) + 1)); - break; - case CustomRoles.Undertaker: - if (Options.UsePets.GetBool() && Main.UndertakerCD.TryGetValue(playerId, out var time20) && !GetPlayerById(playerId).IsModClient()) - ProgressText.Append(" " + string.Format(GetString("CDPT"), Undertaker.AssassinateCooldown.GetInt() - (GetTimeStamp() - time20) + 1)); - break; - case CustomRoles.Killer: - ProgressText.Append(FFAManager.GetDisplayScore(playerId)); - break; - case CustomRoles.Totocalcio: - ProgressText.Append(Totocalcio.GetProgressText(playerId)); - break; - case CustomRoles.Romantic: - ProgressText.Append(Romantic.GetProgressText(playerId)); - break; - case CustomRoles.VengefulRomantic: - ProgressText.Append(VengefulRomantic.GetProgressText(playerId)); - break; - case CustomRoles.Succubus: - ProgressText.Append(Succubus.GetCharmLimit()); - break; - case CustomRoles.CursedSoul: - ProgressText.Append(CursedSoul.GetCurseLimit()); - break; - case CustomRoles.Admirer: - ProgressText.Append(Admirer.GetAdmireLimit()); - break; - case CustomRoles.Infectious: - ProgressText.Append(Infectious.GetBiteLimit()); - break; - case CustomRoles.Monarch: - ProgressText.Append(Monarch.GetKnightLimit()); - break; - case CustomRoles.Deputy: - ProgressText.Append(Deputy.GetHandcuffLimit()); - break; - case CustomRoles.Virus: - ProgressText.Append(Virus.GetInfectLimit()); - break; - case CustomRoles.Ritualist: - ProgressText.Append(Ritualist.GetRitualCount(playerId)); - break; - case CustomRoles.Jackal: - if (Jackal.CanRecruitSidekick.GetBool()) - ProgressText.Append(Jackal.GetRecruitLimit(playerId)); - break; - case CustomRoles.Spiritcaller: - ProgressText.Append(Spiritcaller.GetSpiritLimit()); - break; - default: - //タスクテキスト - var taskState = Main.PlayerStates?[playerId].GetTaskState(); - if (taskState.hasTasks) - { - Color TextColor; - var info = GetPlayerInfoById(playerId); - var TaskCompleteColor = HasTasks(info) ? Color.green : GetRoleColor(role).ShadeColor(0.5f); //タスク完了後の色 - var NonCompleteColor = HasTasks(info) ? Color.yellow : Color.white; //カウントされない人外は白色 + switch (role) + { + case CustomRoles.Arsonist: + var doused = GetDousedPlayerCount(playerId); + if (!Options.ArsonistCanIgniteAnytime.GetBool()) ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Arsonist).ShadeColor(0.25f), $"- {doused.Item1}/{doused.Item2}")); + else ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Arsonist).ShadeColor(0.25f), $"- {doused.Item1}/{Options.ArsonistMaxPlayersToIgnite.GetInt()}")); + break; + case CustomRoles.Sheriff: + if (Sheriff.ShowShotLimit.GetBool()) ProgressText.Append(Sheriff.GetShotLimit(playerId)); + break; + case CustomRoles.Alchemist: + ProgressText.Append(Alchemist.GetProgressText(playerId)); + if (Options.UsePets.GetBool() && Main.AlchemistCD.TryGetValue(playerId, out var time) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Alchemist.VentCooldown.GetInt() - (GetTimeStamp() - time) + 1)); + break; + case CustomRoles.Bandit: + ProgressText.Append(Bandit.GetStealLimit(playerId)); + break; + case CustomRoles.Cleanser: + ProgressText.Append(Cleanser.GetProgressText(playerId)); + break; + case CustomRoles.SerialKiller: + if (SerialKiller.SuicideTimer.ContainsKey(playerId)) + { + int SKTime = SerialKiller.TimeLimit.GetInt() - (int)SerialKiller.SuicideTimer[playerId]; + Color SKColor = SKTime < 10 ? SKTime % 2 == 1 ? Color.yellow : Color.red : Color.white; + if (SKTime <= 20) ProgressText.Append(ColorString(SKColor, $"- {SKTime}s")); + } + break; + case CustomRoles.BountyHunter: + if (BountyHunter.ChangeTimer.ContainsKey(playerId)) + { + int BHTime = (int)(BountyHunter.TargetChangeTime - (float)BountyHunter.ChangeTimer[playerId]); + if (BHTime <= 15) ProgressText.Append(ColorString(Color.white, $"- SWAP: {BHTime}s")); + } + break; + case CustomRoles.Camouflager: + Color TextColorCamo; + if (Camouflager.CamoLimit[playerId] < 1) TextColorCamo = Color.grey; + else TextColorCamo = Color.white; + ProgressText.Append(ColorString(TextColorCamo, $"- {Math.Round(Camouflager.CamoLimit[playerId], 1)}")); + break; + case CustomRoles.Councillor: + Color TextColorCoun; + if (Councillor.MurderLimit[playerId] < 1) TextColorCoun = Color.grey; + else TextColorCoun = Color.white; + ProgressText.Append(ColorString(TextColorCoun, $"- {Math.Round(Councillor.MurderLimit[playerId], 1)}")); + break; + case CustomRoles.Dazzler: + Color TextColorDazzler; + if (Dazzler.DazzleLimit[playerId] < 1) TextColorDazzler = Color.grey; + else TextColorDazzler = Color.white; + ProgressText.Append(ColorString(TextColorDazzler, $"- {Math.Round(Dazzler.DazzleLimit[playerId], 1)}")); + break; + case CustomRoles.Disperser: + Color TextColorDisperser; + if (Disperser.DisperserLimit[playerId] < 1) TextColorDisperser = Color.grey; + else TextColorDisperser = Color.white; + ProgressText.Append(ColorString(TextColorDisperser, $"- {Math.Round(Disperser.DisperserLimit[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.DisperserCD.TryGetValue(playerId, out var time11) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Disperser.DisperserShapeshiftCooldown.GetInt() - (GetTimeStamp() - time11) + 1)); + break; + case CustomRoles.Hangman: + Color TextColorHangman; + if (Hangman.HangLimit[playerId] < 1) TextColorHangman = Color.grey; + else TextColorHangman = Color.white; + ProgressText.Append(ColorString(TextColorHangman, $"- {Math.Round(Hangman.HangLimit[playerId], 1)}")); + break; + case CustomRoles.Twister: + Color TextColorTwister; + if (Twister.TwistLimit[playerId] < 1) TextColorTwister = Color.grey; + else TextColorTwister = Color.white; + ProgressText.Append(ColorString(TextColorTwister, $"- {Math.Round(Twister.TwistLimit[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.TwisterCD.TryGetValue(playerId, out var time12) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Twister.ShapeshiftCooldown.GetInt() - (GetTimeStamp() - time12) + 1)); + break; + case CustomRoles.EvilDiviner: + Color TextColorED; + if (EvilDiviner.DivinationCount[playerId] < 1) TextColorED = Color.grey; + else TextColorED = Color.white; + ProgressText.Append(ColorString(TextColorED, $"- {Math.Round(EvilDiviner.DivinationCount[playerId], 1)}")); + break; + case CustomRoles.Swooper: + Color TextColorSwooper; + if (Swooper.SwoopLimit[playerId] < 1) TextColorSwooper = Color.grey; + else TextColorSwooper = Color.white; + ProgressText.Append(ColorString(TextColorSwooper, $"- {Math.Round(Swooper.SwoopLimit[playerId], 1)}")); + break; + case CustomRoles.Jailor: + ProgressText.Append(Jailor.GetProgressText(playerId)); + break; + case CustomRoles.NiceSwapper: + ProgressText.Append(NiceSwapper.GetNiceSwappermax(playerId)); + break; + case CustomRoles.Veteran: + var taskState2 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor2; + var TaskCompleteColor2 = Color.green; + var NonCompleteColor2 = Color.yellow; + var NormalColor2 = taskState2.IsTaskFinished ? TaskCompleteColor2 : NonCompleteColor2; + TextColor2 = comms ? Color.gray : NormalColor2; + string Completed2 = comms ? "?" : $"{taskState2.CompletedTasksCount}"; + Color TextColor21; + if (Main.VeteranNumOfUsed[playerId] < 1) TextColor21 = Color.red; + else if (Main.VeteranInProtect.ContainsKey(playerId)) TextColor21 = Color.green; + else TextColor21 = Color.white; + ProgressText.Append(ColorString(TextColor2, $"- {Completed2}/{taskState2.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor21, $" - {Math.Round(Main.VeteranNumOfUsed[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.VeteranCD.TryGetValue(playerId, out var time2) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.VeteranSkillCooldown.GetInt() + Options.VeteranSkillDuration.GetInt() - (GetTimeStamp() - time2) + 1)); + break; + case CustomRoles.Grenadier: + var taskState3 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor3; + var TaskCompleteColor3 = Color.green; + var NonCompleteColor3 = Color.yellow; + var NormalColor3 = taskState3.IsTaskFinished ? TaskCompleteColor3 : NonCompleteColor3; + TextColor3 = comms ? Color.gray : NormalColor3; + string Completed3 = comms ? "?" : $"{taskState3.CompletedTasksCount}"; + Color TextColor31; + if (Main.GrenadierNumOfUsed[playerId] < 1) TextColor31 = Color.red; + else if (Main.GrenadierBlinding.ContainsKey(playerId)) TextColor31 = Color.green; + else TextColor31 = Color.white; + ProgressText.Append(ColorString(TextColor3, $"- {Completed3}/{taskState3.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor31, $" - {Math.Round(Main.GrenadierNumOfUsed[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.GrenadierCD.TryGetValue(playerId, out var time3) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.GrenadierSkillCooldown.GetInt() + Options.GrenadierSkillDuration.GetInt() - (GetTimeStamp() - time3) + 1)); + break; + case CustomRoles.Divinator: + var taskState4 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor4; + var TaskCompleteColor4 = Color.green; + var NonCompleteColor4 = Color.yellow; + var NormalColor4 = taskState4.IsTaskFinished ? TaskCompleteColor4 : NonCompleteColor4; + TextColor4 = comms ? Color.gray : NormalColor4; + string Completed4 = comms ? "?" : $"{taskState4.CompletedTasksCount}"; + Color TextColor41; + if (Divinator.CheckLimit[playerId] < 1) TextColor41 = Color.red; + else TextColor41 = Color.white; + ProgressText.Append(ColorString(TextColor4, $"- {Completed4}/{taskState4.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor41, $" - {Math.Round(Divinator.CheckLimit[playerId])}")); + break; + case CustomRoles.DovesOfNeace: + var taskState5 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor5; + var TaskCompleteColor5 = Color.green; + var NonCompleteColor5 = Color.yellow; + var NormalColor5 = taskState5.IsTaskFinished ? TaskCompleteColor5 : NonCompleteColor5; + TextColor5 = comms ? Color.gray : NormalColor5; + string Completed5 = comms ? "?" : $"{taskState5.CompletedTasksCount}"; + Color TextColor51; + if (Main.DovesOfNeaceNumOfUsed[playerId] < 1) TextColor51 = Color.red; + else TextColor51 = Color.white; + ProgressText.Append(ColorString(TextColor5, $"- {Completed5}/{taskState5.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor51, $" - {Math.Round(Main.DovesOfNeaceNumOfUsed[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.DovesOfNeaceCD.TryGetValue(playerId, out var time4) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.DovesOfNeaceCooldown.GetInt() - (GetTimeStamp() - time4) + 1)); + break; + case CustomRoles.TimeMaster: + var taskState6 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor6; + var TaskCompleteColor6 = Color.green; + var NonCompleteColor6 = Color.yellow; + var NormalColor6 = taskState6.IsTaskFinished ? TaskCompleteColor6 : NonCompleteColor6; + TextColor6 = comms ? Color.gray : NormalColor6; + string Completed6 = comms ? "?" : $"{taskState6.CompletedTasksCount}"; + Color TextColor61; + if (Main.TimeMasterNumOfUsed[playerId] < 1) TextColor61 = Color.red; + else if (Main.TimeMasterInProtect.ContainsKey(playerId)) TextColor61 = Color.green; + else TextColor61 = Color.white; + ProgressText.Append(ColorString(TextColor6, $"- {Completed6}/{taskState6.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor61, $" - {Math.Round(Main.TimeMasterNumOfUsed[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.TimeMasterCD.TryGetValue(playerId, out var time5) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.TimeMasterSkillCooldown.GetInt() + Options.TimeMasterSkillDuration.GetInt() - (GetTimeStamp() - time5) + 1)); + break; + case CustomRoles.Mediumshiper: + var taskState7 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor7; + var TaskCompleteColor7 = Color.green; + var NonCompleteColor7 = Color.yellow; + var NormalColor7 = taskState7.IsTaskFinished ? TaskCompleteColor7 : NonCompleteColor7; + TextColor7 = comms ? Color.gray : NormalColor7; + string Completed7 = comms ? "?" : $"{taskState7.CompletedTasksCount}"; + Color TextColor71; + if (Mediumshiper.ContactLimit[playerId] < 1) TextColor71 = Color.red; + else TextColor71 = Color.white; + ProgressText.Append(ColorString(TextColor7, $"- {Completed7}/{taskState7.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor71, $" - {Math.Round(Mediumshiper.ContactLimit[playerId], 1)}")); + break; + case CustomRoles.ParityCop: + var taskState8 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor8; + var TaskCompleteColor8 = Color.green; + var NonCompleteColor8 = Color.yellow; + var NormalColor8 = taskState8.IsTaskFinished ? TaskCompleteColor8 : NonCompleteColor8; + TextColor8 = comms ? Color.gray : NormalColor8; + string Completed8 = comms ? "?" : $"{taskState8.CompletedTasksCount}"; + Color TextColor81; + if (ParityCop.MaxCheckLimit[playerId] < 1) TextColor81 = Color.red; + else TextColor81 = Color.white; + ProgressText.Append(ColorString(TextColor8, $"- {Completed8}/{taskState8.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor81, $" - {Math.Round(ParityCop.MaxCheckLimit[playerId], 1)}")); + break; + case CustomRoles.Oracle: + var taskState9 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor9; + var TaskCompleteColor9 = Color.green; + var NonCompleteColor9 = Color.yellow; + var NormalColor9 = taskState9.IsTaskFinished ? TaskCompleteColor9 : NonCompleteColor9; + TextColor9 = comms ? Color.gray : NormalColor9; + string Completed9 = comms ? "?" : $"{taskState9.CompletedTasksCount}"; + Color TextColor91; + if (Oracle.CheckLimit[playerId] < 1) TextColor91 = Color.red; + else TextColor91 = Color.white; + ProgressText.Append(ColorString(TextColor9, $"- {Completed9}/{taskState9.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor91, $" - {Math.Round(Oracle.CheckLimit[playerId], 1)}")); + break; + case CustomRoles.SabotageMaster: + var taskState10 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor10; + var TaskCompleteColor10 = Color.green; + var NonCompleteColor10 = Color.yellow; + var NormalColor10 = taskState10.IsTaskFinished ? TaskCompleteColor10 : NonCompleteColor10; + TextColor10 = comms ? Color.gray : NormalColor10; + string Completed10 = comms ? "?" : $"{taskState10.CompletedTasksCount}"; + Color TextColor101; + if (SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount > 1) TextColor101 = Color.red; + else TextColor101 = Color.white; + ProgressText.Append(ColorString(TextColor10, $"- {Completed10}/{taskState10.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor101, $" - {Math.Round(SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount, 1)}")); + break; + case CustomRoles.Tracker: + var taskState11 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor11; + var TaskCompleteColor11 = Color.green; + var NonCompleteColor11 = Color.yellow; + var NormalColor11 = taskState11.IsTaskFinished ? TaskCompleteColor11 : NonCompleteColor11; + TextColor11 = comms ? Color.gray : NormalColor11; + string Completed11 = comms ? "?" : $"{taskState11.CompletedTasksCount}"; + Color TextColor111; + if (Tracker.TrackLimit[playerId] < 1) TextColor111 = Color.red; + else TextColor111 = Color.white; + ProgressText.Append(ColorString(TextColor11, $"- {Completed11}/{taskState11.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor111, $" - {Math.Round(Tracker.TrackLimit[playerId], 1)}")); + break; + case CustomRoles.Bloodhound: + var taskState12 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor12; + var TaskCompleteColor12 = Color.green; + var NonCompleteColor12 = Color.yellow; + var NormalColor12 = taskState12.IsTaskFinished ? TaskCompleteColor12 : NonCompleteColor12; + TextColor12 = comms ? Color.gray : NormalColor12; + string Completed12 = comms ? "?" : $"{taskState12.CompletedTasksCount}"; + Color TextColor121; + if (Bloodhound.UseLimit[playerId] < 1) TextColor121 = Color.red; + else TextColor121 = Color.white; + ProgressText.Append(ColorString(TextColor12, $"- {Completed12}/{taskState12.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor121, $" - {Math.Round(Bloodhound.UseLimit[playerId], 1)}")); + break; + case CustomRoles.Chameleon: + var taskState13 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor13; + var TaskCompleteColor13 = Color.green; + var NonCompleteColor13 = Color.yellow; + var NormalColor13 = taskState13.IsTaskFinished ? TaskCompleteColor13 : NonCompleteColor13; + TextColor13 = comms ? Color.gray : NormalColor13; + string Completed13 = comms ? "?" : $"{taskState13.CompletedTasksCount}"; + Color TextColor131; + if (Chameleon.UseLimit[playerId] < 1) TextColor131 = Color.red; + else if (Chameleon.IsInvis(playerId)) TextColor131 = Color.green; + else TextColor131 = Color.white; + ProgressText.Append(ColorString(TextColor13, $"- {Completed13}/{taskState13.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor131, $" - {Math.Round(Chameleon.UseLimit[playerId], 1)}")); + break; + case CustomRoles.Lighter: + var taskState14 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor14; + var TaskCompleteColor14 = Color.green; + var NonCompleteColor14 = Color.yellow; + var NormalColor14 = taskState14.IsTaskFinished ? TaskCompleteColor14 : NonCompleteColor14; + TextColor14 = comms ? Color.gray : NormalColor14; + string Completed14 = comms ? "?" : $"{taskState14.CompletedTasksCount}"; + Color TextColor141; + if (Main.LighterNumOfUsed[playerId] < 1) TextColor141 = Color.red; + else if (Main.Lighter.ContainsKey(playerId)) TextColor141 = Color.green; + else TextColor141 = Color.white; + ProgressText.Append(ColorString(TextColor14, $"- {Completed14}/{taskState14.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor141, $" - {Math.Round(Main.LighterNumOfUsed[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.LighterCD.TryGetValue(playerId, out var time6) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.LighterSkillCooldown.GetInt() + Options.LighterSkillDuration.GetInt() - (GetTimeStamp() - time6) + 1)); + break; + case CustomRoles.Ventguard: + var taskState15 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor15; + var TaskCompleteColor15 = Color.green; + var NonCompleteColor15 = Color.yellow; + var NormalColor15 = taskState15.IsTaskFinished ? TaskCompleteColor15 : NonCompleteColor15; + TextColor15 = comms ? Color.gray : NormalColor15; + string Completed15 = comms ? "?" : $"{taskState15.CompletedTasksCount}"; + Color TextColor151; + if (Main.VentguardNumberOfAbilityUses < 1) TextColor151 = Color.red; + else TextColor151 = Color.white; + ProgressText.Append(ColorString(TextColor15, $"- {Completed15}/{taskState15.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor151, $" - {Math.Round(Main.VentguardNumberOfAbilityUses, 1)}")); + break; + case CustomRoles.SecurityGuard: + var taskState16 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor16; + var TaskCompleteColor16 = Color.green; + var NonCompleteColor16 = Color.yellow; + var NormalColor16 = taskState16.IsTaskFinished ? TaskCompleteColor16 : NonCompleteColor16; + TextColor16 = comms ? Color.gray : NormalColor16; + string Completed16 = comms ? "?" : $"{taskState16.CompletedTasksCount}"; + Color TextColor161; + if (Main.SecurityGuardNumOfUsed[playerId] < 1) TextColor161 = Color.red; + else if (Main.BlockSabo.ContainsKey(playerId)) TextColor161 = Color.green; + else TextColor161 = Color.white; + ProgressText.Append(ColorString(TextColor16, $"- {Completed16}/{taskState16.AllTasksCount}")); + ProgressText.Append(ColorString(TextColor161, $" - {Math.Round(Main.SecurityGuardNumOfUsed[playerId], 1)}")); + if (Options.UsePets.GetBool() && Main.SecurityGuardCD.TryGetValue(playerId, out var time7) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.SecurityGuardSkillCooldown.GetInt() + Options.SecurityGuardSkillDuration.GetInt() - (GetTimeStamp() - time7) + 1)); + break; + //case CustomRoles.Pirate: + // ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Pirate).ShadeColor(0.25f), $"({Pirate.NumWin}/{Pirate.SuccessfulDuelsToWin.GetInt()})")); + // break; + case CustomRoles.Crusader: + ProgressText.Append(Crusader.GetSkillLimit(playerId)); + break; + case CustomRoles.TaskManager: + var taskState1 = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor1; + var TaskCompleteColor1 = Color.green; + var NonCompleteColor1 = Color.yellow; + var NormalColor1 = taskState1.IsTaskFinished ? TaskCompleteColor1 : NonCompleteColor1; + TextColor1 = comms ? Color.gray : NormalColor1; + string Completed1 = comms ? "?" : $"{taskState1.CompletedTasksCount}"; + string totalCompleted1 = comms ? "?" : $"{GameData.Instance.CompletedTasks}"; + ProgressText.Append(ColorString(TextColor1, $"- {Completed1}/{taskState1.AllTasksCount}")); + ProgressText.Append($" - {totalCompleted1}/{GameData.Instance.TotalTasks}"); + break; + case CustomRoles.CameraMan: + ProgressText.Append(CameraMan.GetProgressText(playerId, comms)); + if (Options.UsePets.GetBool() && Main.CameraManCD.TryGetValue(playerId, out var time21) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), CameraMan.VentCooldown.GetInt() - (GetTimeStamp() - time21) + 1)); + break; + case CustomRoles.NiceHacker: + ProgressText.Append(NiceHacker.GetProgressText(playerId, comms)); + if (Options.UsePets.GetBool() && Main.HackerCD.TryGetValue(playerId, out var time8) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), NiceHacker.AbilityCD.GetInt() - (GetTimeStamp() - time8) + 1)); + break; + case CustomRoles.RiftMaker: + ProgressText.Append(RiftMaker.GetProgressText()); + break; + case CustomRoles.Hitman: + ProgressText.Append(Hitman.GetProgressText()); + break; + case CustomRoles.Ricochet: + ProgressText.Append(Ricochet.GetProgressText(playerId, comms)); + break; + case CustomRoles.Doormaster: + ProgressText.Append(Doormaster.GetProgressText(playerId, comms)); + if (Options.UsePets.GetBool() && Main.DoormasterCD.TryGetValue(playerId, out var time9) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Doormaster.VentCooldown.GetInt() - (GetTimeStamp() - time9) + 1)); + break; + case CustomRoles.CopyCat: + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.CopyCat).ShadeColor(0.25f), $"({(CopyCat.MiscopyLimit.TryGetValue(playerId, out var count2) ? count2 : 0)})")); + break; + case CustomRoles.PlagueBearer: + var plagued = PlagueBearer.PlaguedPlayerCount(playerId); + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.PlagueBearer).ShadeColor(0.25f), $"- {plagued.Item1}/{plagued.Item2}")); + break; + case CustomRoles.Doomsayer: + var doomsayerguess = Doomsayer.GuessedPlayerCount(playerId); + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Doomsayer).ShadeColor(0.25f), $"- {doomsayerguess.Item1}/{doomsayerguess.Item2}")); + break; - if (Workhorse.IsThisRole(playerId)) - NonCompleteColor = Workhorse.RoleColor; + case CustomRoles.Sniper: + ProgressText.Append(Sniper.GetBulletCount(playerId)); + if (Options.UsePets.GetBool() && Main.SniperCD.TryGetValue(playerId, out var time13) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.DefaultShapeshiftCooldown.GetInt() - (GetTimeStamp() - time13) + 1)); + break; + case CustomRoles.EvilTracker: + ProgressText.Append(EvilTracker.GetMarker(playerId)); + break; + case CustomRoles.TimeThief: + ProgressText.Append(TimeThief.GetProgressText(playerId)); + break; + case CustomRoles.Mario: + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Mario).ShadeColor(0.25f), $"- {(Main.MarioVentCount.TryGetValue(playerId, out var count) ? count : 0)}/{Options.MarioVentNumWin.GetInt()}")); + break; + case CustomRoles.Vulture: + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Vulture).ShadeColor(0.25f), $"- {(Vulture.BodyReportCount.TryGetValue(playerId, out var count1) ? count1 : 0)}/{Vulture.NumberOfReportsToWin.GetInt()}")); + break; + //case CustomRoles.Masochist: + // ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Masochist).ShadeColor(0.25f), $"- {(Main.MasochistKillMax.TryGetValue(playerId, out var count3) ? count3 : 0)}/{Options.MasochistKillMax.GetInt()}")); + // break; + case CustomRoles.QuickShooter: + ProgressText.Append(QuickShooter.GetShotLimit(playerId)); + if (Options.UsePets.GetBool() && Main.QuickShooterCD.TryGetValue(playerId, out var time14) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), QuickShooter.ShapeshiftCooldown.GetInt() - (GetTimeStamp() - time14) + 1)); + break; + case CustomRoles.SwordsMan: + ProgressText.Append(SwordsMan.GetKillLimit(playerId)); + break; + case CustomRoles.Pelican: + ProgressText.Append(Pelican.GetProgressText(playerId)); + break; + //case CustomRoles.Counterfeiter: + // ProgressText.Append(Counterfeiter.GetSeelLimit(playerId)); + // break; + case CustomRoles.Tether: + ProgressText.Append(Tether.GetProgressText(playerId, comms)); + if (Options.UsePets.GetBool() && Main.TetherCD.TryGetValue(playerId, out var time10) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Tether.VentCooldown.GetInt() - (GetTimeStamp() - time10) + 1)); + break; + case CustomRoles.Spy: + ProgressText.Append(Spy.GetProgressText(playerId, comms)); + break; + case CustomRoles.Aid: + ProgressText.Append(Aid.GetProgressText(playerId, comms)); + break; + case CustomRoles.Pursuer: + ProgressText.Append(Pursuer.GetSeelLimit(playerId)); + break; + case CustomRoles.Revolutionist: + var draw = GetDrawPlayerCount(playerId, out var _); + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Revolutionist).ShadeColor(0.25f), $"- {draw.Item1}/{draw.Item2}")); + break; + case CustomRoles.Gangster: + ProgressText.Append(Gangster.GetRecruitLimit(playerId)); + break; + case CustomRoles.Medic: + ProgressText.Append(Medic.GetSkillLimit(playerId)); + break; + case CustomRoles.CursedWolf: + int SpellCount = Main.CursedWolfSpellCount[playerId]; + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.CursedWolf), $"({SpellCount})")); + break; + case CustomRoles.Jinx: + int JinxSpellCount = Main.JinxSpellCount[playerId]; + ProgressText.Append(ColorString(GetRoleColor(CustomRoles.Jinx), $"({JinxSpellCount})")); + break; + case CustomRoles.Collector: + ProgressText.Append(Collector.GetProgressText(playerId)); + break; + case CustomRoles.Eraser: + ProgressText.Append(Eraser.GetProgressText(playerId)); + break; + //case CustomRoles.NiceEraser: + // ProgressText.Append(NiceEraser.GetProgressText(playerId)); + // break; + case CustomRoles.Hacker: + ProgressText.Append(Hacker.GetHackLimit(playerId)); + break; + case CustomRoles.KB_Normal: + ProgressText.Append(SoloKombatManager.GetDisplayScore(playerId)); + break; + case CustomRoles.Bomber: + if (Options.UsePets.GetBool() && Main.BomberCD.TryGetValue(playerId, out var time15) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.BombCooldown.GetInt() - (GetTimeStamp() - time15) + 1)); + break; + case CustomRoles.Nuker: + if (Options.UsePets.GetBool() && Main.NukerCD.TryGetValue(playerId, out var time16) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.NukeCooldown.GetInt() - (GetTimeStamp() - time16) + 1)); + break; + case CustomRoles.Escapee: + if (Options.UsePets.GetBool() && Main.EscapeeCD.TryGetValue(playerId, out var time17) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.EscapeeSSCD.GetInt() - (GetTimeStamp() - time17) + 1)); + break; + case CustomRoles.Miner: + if (Options.UsePets.GetBool() && Main.MinerCD.TryGetValue(playerId, out var time18) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.MinerSSCD.GetInt() - (GetTimeStamp() - time18) + 1)); + break; + case CustomRoles.Assassin: + if (Options.UsePets.GetBool() && Main.AssassinCD.TryGetValue(playerId, out var time19) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Assassin.AssassinateCooldown.GetInt() - (GetTimeStamp() - time19) + 1)); + break; + case CustomRoles.Undertaker: + if (Options.UsePets.GetBool() && Main.UndertakerCD.TryGetValue(playerId, out var time20) && !GetPlayerById(playerId).IsModClient()) + ProgressText.Append(" " + string.Format(GetString("CDPT"), Undertaker.AssassinateCooldown.GetInt() - (GetTimeStamp() - time20) + 1)); + break; + case CustomRoles.Killer: + ProgressText.Append(FFAManager.GetDisplayScore(playerId)); + break; + case CustomRoles.Totocalcio: + ProgressText.Append(Totocalcio.GetProgressText(playerId)); + break; + case CustomRoles.Romantic: + ProgressText.Append(Romantic.GetProgressText(playerId)); + break; + case CustomRoles.VengefulRomantic: + ProgressText.Append(VengefulRomantic.GetProgressText(playerId)); + break; + case CustomRoles.Succubus: + ProgressText.Append(Succubus.GetCharmLimit()); + break; + case CustomRoles.CursedSoul: + ProgressText.Append(CursedSoul.GetCurseLimit()); + break; + case CustomRoles.Admirer: + ProgressText.Append(Admirer.GetAdmireLimit()); + break; + case CustomRoles.Infectious: + ProgressText.Append(Infectious.GetBiteLimit()); + break; + case CustomRoles.Monarch: + ProgressText.Append(Monarch.GetKnightLimit()); + break; + case CustomRoles.Deputy: + ProgressText.Append(Deputy.GetHandcuffLimit()); + break; + case CustomRoles.Virus: + ProgressText.Append(Virus.GetInfectLimit()); + break; + case CustomRoles.Ritualist: + ProgressText.Append(Ritualist.GetRitualCount(playerId)); + break; + case CustomRoles.Jackal: + if (Jackal.CanRecruitSidekick.GetBool()) + ProgressText.Append(Jackal.GetRecruitLimit(playerId)); + break; + case CustomRoles.Spiritcaller: + ProgressText.Append(Spiritcaller.GetSpiritLimit()); + break; + default: + //タスクテキスト + var taskState = Main.PlayerStates?[playerId].GetTaskState(); + if (taskState.hasTasks) + { + Color TextColor; + var info = GetPlayerInfoById(playerId); + var TaskCompleteColor = HasTasks(info) ? Color.green : GetRoleColor(role).ShadeColor(0.5f); //タスク完了後の色 + var NonCompleteColor = HasTasks(info) ? Color.yellow : Color.white; //カウントされない人外は白色 - var NormalColor = taskState.IsTaskFinished ? TaskCompleteColor : NonCompleteColor; - if (Main.PlayerStates.TryGetValue(playerId, out var ps) && ps.MainRole == CustomRoles.Crewpostor) - NormalColor = Color.red; + if (Workhorse.IsThisRole(playerId)) + NonCompleteColor = Workhorse.RoleColor; - TextColor = comms ? Color.gray : NormalColor; - string Completed = comms ? "?" : $"{taskState.CompletedTasksCount}"; - ProgressText.Append(ColorString(TextColor, $"- {Completed}/{taskState.AllTasksCount}")); - } - break; + var NormalColor = taskState.IsTaskFinished ? TaskCompleteColor : NonCompleteColor; + if (Main.PlayerStates.TryGetValue(playerId, out var ps) && ps.MainRole == CustomRoles.Crewpostor) + NormalColor = Color.red; + + TextColor = comms ? Color.gray : NormalColor; + string Completed = comms ? "?" : $"{taskState.CompletedTasksCount}"; + ProgressText.Append(ColorString(TextColor, $"- {Completed}/{taskState.AllTasksCount}")); + } + break; + } + } + catch (Exception ex) + { + Logger.Error(ex.ToString(), "Utils.GetProgressText"); } if (ProgressText.Length != 0) ProgressText.Insert(0, " "); //空じゃなければ空白を追加 @@ -1836,19 +1849,21 @@ public static class Utils } public static GameData.PlayerInfo GetPlayerInfoById(int PlayerId) => GameData.Instance.AllPlayers.ToArray().Where(info => info.PlayerId == PlayerId).FirstOrDefault(); - private static StringBuilder SelfSuffix = new(); - private static StringBuilder SelfMark = new(20); - private static StringBuilder TargetSuffix = new(); - private static StringBuilder TargetMark = new(20); + private static readonly StringBuilder SelfSuffix = new(); + private static readonly StringBuilder SelfMark = new(20); + private static readonly StringBuilder TargetSuffix = new(); + private static readonly StringBuilder TargetMark = new(20); +#pragma warning disable IDE0060 // Remove unused parameter public static async void NotifyRoles(bool isForMeeting = false, PlayerControl SpecifySeer = null, bool NoCache = false, bool ForceLoop = false, bool CamouflageIsForMeeting = false, bool GuesserIsForMeeting = false) +#pragma warning restore IDE0060 // Remove unused parameter { //if (Options.DeepLowLoad.GetBool()) await Task.Run(() => { DoNotifyRoles(isForMeeting, SpecifySeer, NoCache, ForceLoop, CamouflageIsForMeeting, GuesserIsForMeeting); }); /*else */ - await DoNotifyRoles(isForMeeting, SpecifySeer, NoCache, ForceLoop, CamouflageIsForMeeting, GuesserIsForMeeting); + await DoNotifyRoles(isForMeeting, SpecifySeer, NoCache, /*ForceLoop,*/ CamouflageIsForMeeting, GuesserIsForMeeting); } - public static Task DoNotifyRoles(bool isForMeeting = false, PlayerControl SpecifySeer = null, bool NoCache = false, bool ForceLoop = false, bool CamouflageIsForMeeting = false, bool GuesserIsForMeeting = false) + public static Task DoNotifyRoles(bool isForMeeting = false, PlayerControl SpecifySeer = null, bool NoCache = false, /*bool ForceLoop = false,*/ bool CamouflageIsForMeeting = false, bool GuesserIsForMeeting = false) { if (!AmongUsClient.Instance.AmHost) return Task.CompletedTask; if (Main.AllPlayerControls == null) return Task.CompletedTask; @@ -2568,6 +2583,9 @@ public static class Utils case CustomRoles.NiceHacker: Main.HackerCD.TryAdd(pc.PlayerId, GetTimeStamp()); break; + case CustomRoles.CameraMan: + Main.CameraManCD.TryAdd(pc.PlayerId, GetTimeStamp()); + break; case CustomRoles.Sniper: Main.SniperCD.TryAdd(pc.PlayerId, GetTimeStamp()); break; diff --git a/Patches/ChatControlPatch.cs b/Patches/ChatControlPatch.cs index f51f49e16..ee74df9c1 100644 --- a/Patches/ChatControlPatch.cs +++ b/Patches/ChatControlPatch.cs @@ -47,7 +47,7 @@ class ChatControllerUpdatePatch public class ChatManager { public static bool cancel = false; - private static List chatHistory = new(); + private static readonly List chatHistory = new(); private const int maxHistorySize = 20; public static bool CheckCommand(ref string msg, string command, bool exact = true) { @@ -148,47 +148,76 @@ public class ChatManager for (int i = 0; i < chatHistory.Count; i++) { string entry = chatHistory[i]; - var entryParts = entry.Split(':'); - var senderId = entryParts[0].Trim(); - var senderMessage = entryParts[1].Trim(); - - //foreach (var senderPlayer in Main.AllPlayerControls) - for (int j = 0; j < Main.AllPlayerControls.Count(); j++) + var entryParts = entry.Split(':'); + var senderId = entryParts[0].Trim(); + var senderMessage = entryParts[1].Trim(); + + var senderPlayer = Utils.GetPlayerById(Convert.ToByte(senderId)); + + if (!senderPlayer.IsAlive()) { - var senderPlayer = Main.AllPlayerControls.ElementAt(j); - if (senderPlayer.PlayerId.ToString() == senderId) - { - if (!senderPlayer.IsAlive()) - { - //var deathReason = (PlayerState.DeathReason)senderPlayer.PlayerId; - senderPlayer.Revive(); + senderPlayer.Revive(); + DestroyableSingleton.Instance.Chat.AddChat(senderPlayer, senderMessage); - DestroyableSingleton.Instance.Chat.AddChat(senderPlayer, senderMessage); - - var writer = CustomRpcSender.Create("MessagesToSend", SendOption.None); - writer.StartMessage(-1); - writer.StartRpc(senderPlayer.NetId, (byte)RpcCalls.SendChat) - .Write(senderMessage) - .EndRpc(); - writer.EndMessage(); - writer.SendMessage(); - senderPlayer.Die(DeathReason.Kill, true); - //Main.PlayerStates[senderPlayer.PlayerId].deathReason = deathReason; - } - else - { - DestroyableSingleton.Instance.Chat.AddChat(senderPlayer, senderMessage); - var writer = CustomRpcSender.Create("MessagesToSend", SendOption.None); - writer.StartMessage(-1); - writer.StartRpc(senderPlayer.NetId, (byte)RpcCalls.SendChat) - .Write(senderMessage) - .EndRpc(); - writer.EndMessage(); - writer.SendMessage(); - } - } + var writer = CustomRpcSender.Create("MessagesToSend", SendOption.None); + writer.StartMessage(-1); + writer.StartRpc(senderPlayer.NetId, (byte)RpcCalls.SendChat) + .Write(senderMessage) + .EndRpc(); + writer.EndMessage(); + writer.SendMessage(); + senderPlayer.Die(DeathReason.Kill, true); } + else + { + DestroyableSingleton.Instance.Chat.AddChat(senderPlayer, senderMessage); + var writer = CustomRpcSender.Create("MessagesToSend", SendOption.None); + writer.StartMessage(-1); + writer.StartRpc(senderPlayer.NetId, (byte)RpcCalls.SendChat) + .Write(senderMessage) + .EndRpc(); + writer.EndMessage(); + writer.SendMessage(); + } + + //foreach (var senderPlayer in Main.AllPlayerControls) + //for (int j = 0; j < Main.AllPlayerControls.Count(); j++) + //{ + // var senderPlayer = Main.AllPlayerControls.ElementAt(j); + // if (senderPlayer.PlayerId.ToString() == senderId) + // { + // if (!senderPlayer.IsAlive()) + // { + // var deathReason = (PlayerState.DeathReason)senderPlayer.PlayerId; + // senderPlayer.Revive(); + + + // DestroyableSingleton.Instance.Chat.AddChat(senderPlayer, senderMessage); + + // var writer = CustomRpcSender.Create("MessagesToSend", SendOption.None); + // writer.StartMessage(-1); + // writer.StartRpc(senderPlayer.NetId, (byte)RpcCalls.SendChat) + // .Write(senderMessage) + // .EndRpc(); + // writer.EndMessage(); + // writer.SendMessage(); + // senderPlayer.Die((DeathReason)deathReason, true); + // //Main.PlayerStates[senderPlayer.PlayerId].deathReason = deathReason; + // } + // else + // { + // DestroyableSingleton.Instance.Chat.AddChat(senderPlayer, senderMessage); + // var writer = CustomRpcSender.Create("MessagesToSend", SendOption.None); + // writer.StartMessage(-1); + // writer.StartRpc(senderPlayer.NetId, (byte)RpcCalls.SendChat) + // .Write(senderMessage) + // .EndRpc(); + // writer.EndMessage(); + // writer.SendMessage(); + // } + // } + //} } } } \ No newline at end of file diff --git a/Patches/ControlPatch.cs b/Patches/ControlPatch.cs index 5d85ea8aa..1f4920d24 100644 --- a/Patches/ControlPatch.cs +++ b/Patches/ControlPatch.cs @@ -17,7 +17,7 @@ internal class ControllerManagerUpdatePatch public static List addDes = new(); public static int addonIndex = -1; - public static void Postfix(ControllerManager __instance) + public static void Postfix(/*ControllerManager __instance*/) { //切换自定义设置的页面 if (GameStates.IsLobby) @@ -35,7 +35,7 @@ internal class ControllerManagerUpdatePatch //捕捉全屏快捷键 if (GetKeysDown(KeyCode.LeftAlt, KeyCode.Return)) { - new LateTask(SetResolutionManager.Postfix, 0.01f, "Fix Button Position"); + _ = new LateTask(SetResolutionManager.Postfix, 0.01f, "Fix Button Position"); } //职业介绍 if (Input.GetKeyDown(KeyCode.F1) && GameStates.InGame && Options.CurrentGameMode == CustomGameMode.Standard) diff --git a/Patches/ExilePatch.cs b/Patches/ExilePatch.cs index cc92b234c..6e6bef2ff 100644 --- a/Patches/ExilePatch.cs +++ b/Patches/ExilePatch.cs @@ -9,7 +9,10 @@ namespace TOHE; class ExileControllerWrapUpPatch { - public static GameData.PlayerInfo AntiBlackout_LastExiled; + private static GameData.PlayerInfo antiBlackout_LastExiled; + + public static GameData.PlayerInfo AntiBlackout_LastExiled { get => antiBlackout_LastExiled; set => antiBlackout_LastExiled = value; } + [HarmonyPatch(typeof(ExileController), nameof(ExileController.WrapUp))] class BaseExileControllerPatch { @@ -89,7 +92,7 @@ class ExileControllerWrapUpPatch //判断处刑人胜利 if (Executioner.CheckExileTarget(exiled, DecidedWinner)) DecidedWinner = true; - if (Lawyer.CheckExileTarget(exiled, DecidedWinner)) DecidedWinner = false; + if (Lawyer.CheckExileTarget(exiled/*, DecidedWinner*/)) DecidedWinner = false; //判断恐怖分子胜利 if (role == CustomRoles.Terrorist) Utils.CheckTerroristWin(exiled); diff --git a/Patches/GameStartManagerPatch.cs b/Patches/GameStartManagerPatch.cs index 48e92b9a0..aff807b48 100644 --- a/Patches/GameStartManagerPatch.cs +++ b/Patches/GameStartManagerPatch.cs @@ -251,7 +251,7 @@ public class GameStartRandomMap __instance.ReallyBegin(false); return false; } - public static bool Prefix(GameStartRandomMap __instance) + public static bool Prefix(/*GameStartRandomMap __instance*/) { bool continueStart = true; if (Options.RandomMapsMode.GetBool()) diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 5be1d32c2..f8a0f404e 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -452,6 +452,7 @@ class HudManagerPatch CustomRoles.Wildling => Wildling.GetHudText(player), CustomRoles.Doormaster => Doormaster.GetHudText(player), CustomRoles.Tether => Tether.GetHudText(player), + CustomRoles.CameraMan => !Options.UsePets.GetBool() || !Main.CameraManCD.TryGetValue(player.PlayerId, out var cd) ? string.Empty : string.Format(GetString("CDPT"), CameraMan.VentCooldown.GetInt() - (now - cd) + 1), CustomRoles.Mayor => !Options.UsePets.GetBool() || !Main.MayorCD.TryGetValue(player.PlayerId, out var cd) ? string.Empty : string.Format(GetString("CDPT"), Options.DefaultKillCooldown - (now - cd) + 1), CustomRoles.Paranoia => !Options.UsePets.GetBool() || !Main.ParanoiaCD.TryGetValue(player.PlayerId, out var cd) ? string.Empty : string.Format(GetString("CDPT"), Options.ParanoiaVentCooldown.GetInt() - (now - cd) + 1), CustomRoles.Veteran => !Options.UsePets.GetBool() || !Main.VeteranCD.TryGetValue(player.PlayerId, out var cd) ? string.Empty : string.Format(GetString("CDPT"), Options.VeteranSkillCooldown.GetInt() - (now - cd) + 1), diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index 415530063..a5dcbafe5 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -564,20 +564,20 @@ class CheckForEndVotingPatch if (CustomRoles.Lovers.IsEnable() && !Main.isLoversDead && Main.LoversPlayers.Find(lp => lp.PlayerId == playerId) != null) FixedUpdatePatch.LoversSuicide(playerId, true); //道連れチェック - RevengeOnExile(playerId, deathReason); + RevengeOnExile(playerId/*, deathReason*/); } } - private static void RevengeOnExile(byte playerId, PlayerState.DeathReason deathReason) + private static void RevengeOnExile(byte playerId/*, PlayerState.DeathReason deathReason*/) { var player = Utils.GetPlayerById(playerId); if (player == null) return; - var target = PickRevengeTarget(player, deathReason); + var target = PickRevengeTarget(player/*, deathReason*/); if (target == null) return; TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.Revenge, target.PlayerId); target.SetRealKiller(player); Logger.Info($"{player.GetNameWithRole()}の道連れ先:{target.GetNameWithRole()}", "RevengeOnExile"); } - private static PlayerControl PickRevengeTarget(PlayerControl exiledplayer, PlayerState.DeathReason deathReason)//道連れ先選定 + private static PlayerControl PickRevengeTarget(PlayerControl exiledplayer/*, PlayerState.DeathReason deathReason*/)//道連れ先選定 { List TargetList = new(); foreach (var candidate in Main.AllAlivePlayerControls) @@ -769,6 +769,8 @@ class MeetingHudStartPatch AddMsg(string.Format(GetString("MediumshipNotifyTarget"), Main.AllPlayerNames[Mediumshiper.ContactPlayer[pc.PlayerId]]), pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Mediumshiper), GetString("MediumshipTitle"))); if (Main.VirusNotify.ContainsKey(pc.PlayerId)) AddMsg(Main.VirusNotify[pc.PlayerId], pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Virus), GetString("VirusNoticeTitle"))); + if (Enigma.MsgToSend.ContainsKey(pc.PlayerId)) + AddMsg(Enigma.MsgToSend[pc.PlayerId], pc.PlayerId, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Enigma), Enigma.MsgToSendTitle[pc.PlayerId])); } //宝箱怪的消息(合并) if (MimicMsg != string.Empty) @@ -789,9 +791,10 @@ class MeetingHudStartPatch Main.DetectiveNotify.Clear(); Main.VirusNotify.Clear(); Mortician.msgToSend.Clear(); + Enigma.MsgToSend.Clear(); //Pirate.OnMeetingStart(); } - public static void Prefix(MeetingHud __instance) + public static void Prefix(/*MeetingHud __instance*/) { Logger.Info("------------会议开始------------", "Phase"); ChatUpdatePatch.DoBlockChat = true; diff --git a/Patches/OutroPatch.cs b/Patches/OutroPatch.cs index be37b9f54..7a7f35cd9 100644 --- a/Patches/OutroPatch.cs +++ b/Patches/OutroPatch.cs @@ -38,7 +38,7 @@ class EndGamePatch 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; + if (!KillLog.Contains('\n')) KillLog = string.Empty; Main.NormalOptions.KillCooldown = Options.DefaultKillCooldown; //winnerListリセット diff --git a/Patches/PetActionsPatch.cs b/Patches/PetActionsPatch.cs index 3e029261f..f8967e2fb 100644 --- a/Patches/PetActionsPatch.cs +++ b/Patches/PetActionsPatch.cs @@ -19,7 +19,7 @@ namespace TOHE; [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.TryPet))] class LocalPetPatch { - private static System.Collections.Generic.Dictionary LastProcess = new(); + private static readonly System.Collections.Generic.Dictionary LastProcess = new(); public static bool Prefix(PlayerControl __instance) { if (!Options.UsePets.GetBool()) return true; @@ -86,7 +86,6 @@ class ExternalRpcPetPatch break; } Doormaster.OnEnterVent(pc); - pc.RpcResetAbilityCooldown(); break; case CustomRoles.Tether: if (Main.TetherCD.ContainsKey(pc.PlayerId)) @@ -95,7 +94,14 @@ class ExternalRpcPetPatch break; } Tether.OnEnterVent(pc, 0, true); - pc.RpcResetAbilityCooldown(); + break; + case CustomRoles.CameraMan: + if (Main.CameraManCD.ContainsKey(pc.PlayerId)) + { + //if (!NameNotifyManager.Notice.ContainsKey(pc.PlayerId)) pc.Notify(GetString("AbilityOnCooldown")); + break; + } + CameraMan.OnEnterVent(pc); break; case CustomRoles.Mayor: if (Main.MayorUsedButtonCount.TryGetValue(pc.PlayerId, out var count) && count < Options.MayorNumOfUseButton.GetInt() && !Main.MayorCD.ContainsKey(pc.PlayerId)) @@ -134,7 +140,6 @@ class ExternalRpcPetPatch pc.RPCPlayCustomSound("Gunload"); pc.Notify(GetString("VeteranOnGuard"), Options.VeteranSkillDuration.GetFloat()); Main.VeteranCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); - pc.RpcResetAbilityCooldown(); pc.MarkDirtySettings(); } else @@ -167,7 +172,6 @@ class ExternalRpcPetPatch pc.RPCPlayCustomSound("FlashBang"); pc.Notify(GetString("GrenadierSkillInUse"), Options.GrenadierSkillDuration.GetFloat()); Main.GrenadierCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); - pc.RpcResetAbilityCooldown(); Main.GrenadierNumOfUsed[pc.PlayerId] -= 1; Utils.MarkEveryoneDirtySettingsV3(); } @@ -189,7 +193,6 @@ class ExternalRpcPetPatch Main.Lighter.Add(pc.PlayerId, Utils.GetTimeStamp()); pc.Notify(GetString("LighterSkillInUse"), Options.LighterSkillDuration.GetFloat()); Main.LighterCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); - pc.RpcResetAbilityCooldown(); Main.LighterNumOfUsed[pc.PlayerId] -= 1; pc.MarkDirtySettings(); } @@ -212,7 +215,6 @@ class ExternalRpcPetPatch Main.BlockSabo.Add(pc.PlayerId, Utils.GetTimeStamp()); pc.Notify(GetString("SecurityGuardSkillInUse"), Options.SecurityGuardSkillDuration.GetFloat()); Main.SecurityGuardCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); - pc.RpcResetAbilityCooldown(); Main.SecurityGuardNumOfUsed[pc.PlayerId] -= 1; } else @@ -251,12 +253,10 @@ class ExternalRpcPetPatch pc.RPCPlayCustomSound("Dove"); pc.Notify(string.Format(GetString("DovesOfNeaceOnGuard"), Main.DovesOfNeaceNumOfUsed[pc.PlayerId])); Main.DovesOfNeaceCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); - pc.RpcResetAbilityCooldown(); } break; case CustomRoles.Alchemist: Alchemist.OnEnterVent(pc, 0, true); - pc.RpcResetAbilityCooldown(); break; case CustomRoles.TimeMaster: if (Main.TimeMasterInProtect.ContainsKey(pc.PlayerId)) break; @@ -273,7 +273,6 @@ class ExternalRpcPetPatch //if (!pc.IsModClient()) pc.RpcGuardAndKill(pc); pc.Notify(GetString("TimeMasterOnGuard"), Options.TimeMasterSkillDuration.GetFloat()); Main.TimeMasterCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); - pc.RpcResetAbilityCooldown(); foreach (var player in Main.AllPlayerControls) { if (Main.TimeMasterBackTrack.ContainsKey(player.PlayerId)) @@ -298,7 +297,6 @@ class ExternalRpcPetPatch break; case CustomRoles.NiceHacker: NiceHacker.OnEnterVent(pc); - pc.RpcResetAbilityCooldown(); break; // Impostors diff --git a/Patches/PlayerContorolPatch.cs b/Patches/PlayerContorolPatch.cs index 4c4cf7cd9..3bb64fe54 100644 --- a/Patches/PlayerContorolPatch.cs +++ b/Patches/PlayerContorolPatch.cs @@ -1737,6 +1737,7 @@ class ReportDeadBodyPatch Camouflager.OnReportDeadBody(); if (Bandit.IsEnable) Bandit.OnReportDeadBody(); + if (Enigma.IsEnable) Enigma.OnReportDeadBody(player, target); if (Psychic.IsEnable) Psychic.OnReportDeadBody(); if (BountyHunter.IsEnable) BountyHunter.OnReportDeadBody(); if (HeadHunter.IsEnable) HeadHunter.OnReportDeadBody(); @@ -1772,7 +1773,7 @@ class ReportDeadBodyPatch if (Tracker.IsEnable) Tracker.OnReportDeadBody(); if (Mortician.IsEnable) Mortician.OnReportDeadBody(player, target); - if (Tracefinder.IsEnable) Tracefinder.OnReportDeadBody(player, target); + if (Tracefinder.IsEnable) Tracefinder.OnReportDeadBody(/*player, target*/); if (Mediumshiper.IsEnable) Mediumshiper.OnReportDeadBody(target); if (Spiritualist.IsEnable) Spiritualist.OnReportDeadBody(target); @@ -1830,11 +1831,11 @@ class ReportDeadBodyPatch [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.FixedUpdate))] class FixedUpdatePatch { - private static StringBuilder Mark = new(20); - private static StringBuilder Suffix = new(120); + private static readonly StringBuilder Mark = new(20); + private static readonly StringBuilder Suffix = new(120); private static int LevelKickBufferTime = 10; - private static Dictionary BufferTime = new(); - private static Dictionary DeadBufferTime = new(); + private static readonly Dictionary BufferTime = new(); + private static readonly Dictionary DeadBufferTime = new(); public static async void Postfix(PlayerControl __instance) { @@ -1925,16 +1926,39 @@ class FixedUpdatePatch } if (DoubleTrigger.FirstTriggerTimer.Any()) DoubleTrigger.OnFixedUpdate(player); - if (player.Is(CustomRoles.Vampire)) Vampire.OnFixedUpdate(player); - if (player.Is(CustomRoles.Poisoner)) Poisoner.OnFixedUpdate(player); - if (player.Is(CustomRoles.BountyHunter) && !lowLoad) BountyHunter.FixedUpdate(player); - if (player.Is(CustomRoles.Glitch) && !lowLoad) Glitch.UpdateHackCooldown(player); - if (player.Is(CustomRoles.Aid) && !lowLoad) Aid.OnFixedUpdate(player); - if (player.Is(CustomRoles.Spy) && !lowLoad) Spy.OnFixedUpdate(player); - if (player.Is(CustomRoles.RiftMaker) && !lowLoad) RiftMaker.OnFixedUpdate(player); - if (player.Is(CustomRoles.Mastermind) && !lowLoad) Mastermind.OnFixedUpdate(); - if (player.Is(CustomRoles.SerialKiller)) SerialKiller.FixedUpdate(player); - if (player.Is(CustomRoles.Gambler) && !lowLoad) Gambler.OnFixedUpdate(player); + switch (player.GetCustomRole()) + { + case CustomRoles.Vampire: + Vampire.OnFixedUpdate(player); + break; + case CustomRoles.Poisoner: + Poisoner.OnFixedUpdate(player); + break; + case CustomRoles.BountyHunter when !lowLoad: + BountyHunter.FixedUpdate(player); + break; + case CustomRoles.Glitch when !lowLoad: + Glitch.UpdateHackCooldown(player); + break; + case CustomRoles.Aid when !lowLoad: + Aid.OnFixedUpdate(player); + break; + case CustomRoles.Spy when !lowLoad: + Spy.OnFixedUpdate(player); + break; + case CustomRoles.RiftMaker when !lowLoad: + RiftMaker.OnFixedUpdate(player); + break; + case CustomRoles.Mastermind when !lowLoad: + Mastermind.OnFixedUpdate(); + break; + case CustomRoles.SerialKiller: + SerialKiller.FixedUpdate(player); + break; + case CustomRoles.Gambler when !lowLoad: + Gambler.OnFixedUpdate(player); + break; + } if (GameStates.IsInTask && player.Is(CustomRoles.PlagueBearer) && PlagueBearer.IsPlaguedAll(player)) { player.RpcSetCustomRole(CustomRoles.Pestilence); @@ -1966,6 +1990,14 @@ class FixedUpdatePatch } if (Main.TetherCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); break; + case CustomRoles.CameraMan: + if (Main.CameraManCD.TryGetValue(player.PlayerId, out var cm) && cm + CameraMan.VentCooldown.GetInt() < Utils.GetTimeStamp()) + { + Main.CameraManCD.Remove(player.PlayerId); + Utils.NotifyRoles(SpecifySeer: player); + } + if (Main.CameraManCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + break; case CustomRoles.Mayor: if (Main.MayorCD.TryGetValue(player.PlayerId, out var my) && my + Options.DefaultKillCooldown < Utils.GetTimeStamp()) { @@ -3428,14 +3460,14 @@ class CoEnterVentPatch [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.SetName))] class SetNamePatch { - public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)] string name) + public static void Postfix(/*PlayerControl __instance, [HarmonyArgument(0)] string name*/) { } } [HarmonyPatch(typeof(GameData), nameof(GameData.CompleteTask))] class GameDataCompleteTaskPatch { - public static void Postfix(PlayerControl pc, uint taskId) + public static void Postfix(PlayerControl pc/*, uint taskId*/) { Logger.Info($"TaskComplete:{pc.GetNameWithRole()}", "CompleteTask"); Main.PlayerStates[pc.PlayerId].UpdateTask(pc); @@ -3445,7 +3477,7 @@ class GameDataCompleteTaskPatch [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CompleteTask))] class PlayerControlCompleteTaskPatch { - public static bool Prefix(PlayerControl __instance, uint idx) + public static bool Prefix(PlayerControl __instance/*, uint idx*/) { var player = __instance; diff --git a/Patches/RecomputeTaskPatch.cs b/Patches/RecomputeTaskPatch.cs index bb8ad66a9..fd719b237 100644 --- a/Patches/RecomputeTaskPatch.cs +++ b/Patches/RecomputeTaskPatch.cs @@ -34,7 +34,7 @@ class CustomTaskCountsPatch [HarmonyPatch(typeof(GameData), nameof(GameData.CompleteTask))] class CompleteTaskPatch { - public static void Postfix(GameData __instance) + public static void Postfix(/*GameData __instance*/) { } } \ No newline at end of file diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs index b464623ac..981909990 100644 --- a/Patches/ShipStatusPatch.cs +++ b/Patches/ShipStatusPatch.cs @@ -11,7 +11,7 @@ namespace TOHE; [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.FixedUpdate))] class ShipFixedUpdatePatch { - public static void Postfix(ShipStatus __instance) + public static void Postfix(/*ShipStatus __instance*/) { //ここより上、全員が実行する if (!AmongUsClient.Instance.AmHost) return; @@ -133,7 +133,7 @@ class RepairSystemPatch return true; } - public static void Postfix(ShipStatus __instance) + public static void Postfix(/*ShipStatus __instance*/) { Camouflage.CheckCamouflage(); } @@ -161,7 +161,7 @@ class RepairSystemPatch [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.CloseDoorsOfType))] class CloseDoorsPatch { - public static bool Prefix(ShipStatus __instance, SystemTypes room) + public static bool Prefix(/*ShipStatus __instance, SystemTypes room*/) { if (Main.BlockSabo.Any()) return false; if (Options.DisableCloseDoor.GetBool()) return false; @@ -172,7 +172,7 @@ class CloseDoorsPatch [HarmonyPatch(typeof(SwitchSystem), nameof(SwitchSystem.RepairDamage))] class SwitchSystemRepairPatch { - public static bool Prefix(SwitchSystem __instance, [HarmonyArgument(0)] PlayerControl player, [HarmonyArgument(1)] byte amount) + public static bool Prefix(/*SwitchSystem __instance,*/ [HarmonyArgument(0)] PlayerControl player/*, [HarmonyArgument(1)] byte amount*/) { if (player.Is(CustomRoles.Fool)) return false; else return true; @@ -220,7 +220,7 @@ class StartPatch [HarmonyPatch(typeof(ShipStatus), nameof(ShipStatus.StartMeeting))] class StartMeetingPatch { - public static void Prefix(ShipStatus __instance, PlayerControl reporter, GameData.PlayerInfo target) + public static void Prefix(/*ShipStatus __instance, PlayerControl reporter,*/ GameData.PlayerInfo target) { MeetingStates.ReportTarget = target; MeetingStates.DeadBodies = UnityEngine.Object.FindObjectsOfType(); diff --git a/Patches/UsablesPatch.cs b/Patches/UsablesPatch.cs index 322005d82..27f5dae1b 100644 --- a/Patches/UsablesPatch.cs +++ b/Patches/UsablesPatch.cs @@ -7,7 +7,7 @@ namespace TOHE; [HarmonyPatch(typeof(Console), nameof(Console.CanUse))] class CanUsePatch { - public static bool Prefix(ref float __result, Console __instance, [HarmonyArgument(0)] GameData.PlayerInfo pc, [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse) + public static bool Prefix(/*ref float __result,*/ Console __instance, /*[HarmonyArgument(0)] GameData.PlayerInfo pc,*/ [HarmonyArgument(1)] out bool canUse, [HarmonyArgument(2)] out bool couldUse) { canUse = couldUse = false; //こいつをfalseでreturnしても、タスク(サボ含む)以外の使用可能な物は使えるまま(ボタンなど) diff --git a/Patches/onGameStartedPatch.cs b/Patches/onGameStartedPatch.cs index 163ef4d9a..88c8b41f5 100644 --- a/Patches/onGameStartedPatch.cs +++ b/Patches/onGameStartedPatch.cs @@ -285,6 +285,7 @@ internal class ChangeRoleSettings Jinx.Init(); DoubleShot.Init(); Dazzler.Init(); + CameraMan.Init(); Hitman.Init(); Gambler.Init(); RiftMaker.Init(); @@ -304,6 +305,7 @@ internal class ChangeRoleSettings ParityCop.Init(); // *giggle* party cop //Baker.Init(); Spiritcaller.Init(); + Enigma.Init(); Lurker.Init(); PlagueBearer.Init(); //Reverie.Init(); @@ -861,9 +863,15 @@ internal class SelectRolesPatch case CustomRoles.Dazzler: Dazzler.Add(pc.PlayerId); break; + case CustomRoles.CameraMan: + CameraMan.Add(pc.PlayerId); + break; case CustomRoles.Hitman: Hitman.Add(pc.PlayerId); break; + case CustomRoles.Enigma: + Enigma.Add(pc.PlayerId); + break; case CustomRoles.Gambler: Gambler.Add(pc.PlayerId); break; diff --git a/Resources/String.csv b/Resources/String.csv index 8e3f7adf6..97a89bed9 100644 --- a/Resources/String.csv +++ b/Resources/String.csv @@ -158,9 +158,9 @@ "Puppeteer","傀儡师","Puppeteer","Кукловод","傀儡師","Titiritero" "TimeThief","蚀时者","Time Thief","Вор Времени","時間竊賊","Ladrón del Tiempo" "Sniper","狙击手","Sniper","Снайпер","狙擊手","Sniper" -"EvilTracker","邪恶追踪者","Agent","Злой Трекер","邪惡追蹤者","Rastreador Malvado" +"EvilTracker","邪恶追踪者","Evil Tracker","Злой Трекер","邪惡追蹤者","Rastreador Malvado" "EvilGuesser","邪恶赌怪","Evil Guesser","Злой Угадыватель","邪惡賭怪","Adivinador Malvado" -"AntiAdminer","监管者","Disruptor","Анти Админер","監管者","Disruptor" +"AntiAdminer","监管者","Anti Adminer","Анти Админер","監管者","Disruptor" "Sans","狂妄杀手","Arrogance","Высокомер","狂妄殺手","Sans" "Bomber","自爆兵","Bomber","Бомбер","自爆兵","Bombero" "Scavenger","清道夫","Scavenger","Уборщик","清道夫","Carroñero" @@ -721,9 +721,9 @@ "PuppeteerInfoLong","(内鬼阵营):\n傀儡师的操控对象会击杀其遇到的下一个船员。若后者在接触的同时死亡,则前者死亡。傀儡师不可以正常击杀。请注意,摆烂人不会替你办事,操控摆烂人只会浪费你的时间。","(Impostors):\nThe player controlled by the Puppeteer will kill the next non-impostor player that shows up closest to them. If the latter dies on contact, the former dies. Puppeteers cannot kill normally. Note that Lazy Guy will not do things for you, controlling Lazy Guy will only waste your time."," (Предатель):\nКукловод может совершить убийство с помощью помеченного игрока, но не может убивать как обычный Предатель. \nЕсли цель убивает противника и он срабатывает в момент убийства цели, эффект отразится на цели. \nВы не можете совершать обычные убийства.","(偽裝者陣營):\n傀儡師按下殺人按鈕時將會操控離他最近的玩家(與術士下咒差不多),接著如果在殺人範圍內碰到非偽裝者陣營的人,被操控的玩家將會直接殺死被害者,並且效果不再持續。\n請注意: 擺爛人不會替你殺人","(内鬼阵营):\n傀儡师的操控对象会击杀其遇到的下一个船员。若后者在接触的同时死亡,则前者死亡。傀儡师不可以正常击杀。请注意,摆烂人不会替你办事,操控摆烂人只会浪费你的时间。" "TimeThiefInfoLong","(内鬼阵营):\n蚀时者每击杀一个人,会议时间就将减少一定时间。如果蚀时者死亡,会议时间会恢复正常。","(Impostors):\nEvery time the Time Thief kills a player, the meeting time will be reduced by a certain amount of time. If the Time Thief dies, the meeting time will return to normal."," (Предатель):\nКаждое убийство Вора Времени сокращает время обсуждения и голосования на собраниях. \nВ зависимости от настроек потерянное время возвращается после того, как он будет убит или изгнан.","(偽裝者陣營):\n時間竊賊每殺死一個人,那麼會議時間就會減少一定時間,如果時間竊賊死亡,那麼會議時間將會恢復。","(内鬼阵营):\n蚀时者每击杀一个人,会议时间就将减少一定时间。如果蚀时者死亡,会议时间会恢复正常。" "SniperInfoLong","(内鬼阵营):\n狙击手拥有远距离射杀的能力。方法为:进入变形到解除变形的位置连成一条线,这条线包括这条线的射线上距离最近的玩家会被狙杀。狙击手在子弹用完后可以进行正常击杀。","(Impostors):\nYou can shoot players from far away.\nYou have to shapeshift twice/pet your pet twice to make a successful snipe.\nImagine an arrow pointing from your first shapeshift/petting location towards your unshift/second petting location.\nThat will be the direction in which the snipe will be made.\nThe snipe kills the first person in its path.\nYou cannot kill normally until you use up all of your ammo."," (Предатель):\nСнайпер может стрелять в игроков на расстоянии. \nОн убивает игрока который, находится с ним на одной линии, от точки Морфа до точки возвращения в свой облик. \nОн может совершать обычные убийства после того, как все его патроны закончатся.","(偽裝者陣營):\n狙擊手擁有遠距離狙殺的技能,當狙擊手變形時會標記一個點(標記A),解除變形時也會標記一個點(標記B),標記A到標記B即為彈道,\n子彈將由標記A穿越彈道後再從標記B打出,並狙殺離這條彈道上最近的人(若有人處於彈道中則不會被狙殺),狙擊手在子彈用完之後可以正常殺人。","(内鬼阵营):\n狙击手拥有远距离射杀的能力。方法为:进入变形到解除变形的位置连成一条线,这条线包括这条线的射线上距离最近的玩家会被狙杀。狙击手在子弹用完后可以进行正常击杀。" -"EvilTrackerInfoLong","(内鬼阵营):\n追踪者可以追踪其他人,追踪者可以变形为某个人以切换追踪目标为变形的目标。玩家名称下面的箭头代表着目标的方向。当内鬼队友杀人时,追踪者将会看到击杀闪烁提示。","(Impostors):\nThe Agent can track other people, and the Agent can shapeshift into someone to switch the tracking target to the shapeshift target (You will immediately unshift after performing shapeshift). The arrow below the Agent's name indicates the direction of the target. When the Agent's teammate kills, the Agent will see a kill flash."," (Предатель):\nЗлой Трекер может отслеживать других игроков. \nОн может видеть стрелки, которые указывают на Предателей или на того, в кого он превратился. \nОн может видеть когда было совершено убийство с помощью вспышки убийства.","(偽裝者陣營):\n邪惡追蹤者可以通過變形來指定一個追蹤目標,變形後將會解除變形,並且玩家名稱會出現一個箭頭指向目標,當隊友殺人時,邪惡追蹤者將會看到螢幕閃爍為提示。","(内鬼阵营):\n追踪者可以追踪其他人,追踪者可以变形为某个人以切换追踪目标为变形的目标。玩家名称下面的箭头代表着目标的方向。当内鬼队友杀人时,追踪者将会看到击杀闪烁提示。" +"EvilTrackerInfoLong","(内鬼阵营):\n追踪者可以追踪其他人,追踪者可以变形为某个人以切换追踪目标为变形的目标。玩家名称下面的箭头代表着目标的方向。当内鬼队友杀人时,追踪者将会看到击杀闪烁提示。","(Impostors):\nThe Evil Tracker can track other people, and the Evil Tracker can shapeshift into someone to switch the tracking target to the shapeshift target (You will immediately unshift after performing shapeshift). The arrow below the Evil Tracker's name indicates the direction of the target. When the Evil Tracker's teammate kills, the Evil Tracker will see a kill flash."," (Предатель):\nЗлой Трекер может отслеживать других игроков. \nОн может видеть стрелки, которые указывают на Предателей или на того, в кого он превратился. \nОн может видеть когда было совершено убийство с помощью вспышки убийства.","(偽裝者陣營):\n邪惡追蹤者可以通過變形來指定一個追蹤目標,變形後將會解除變形,並且玩家名稱會出現一個箭頭指向目標,當隊友殺人時,邪惡追蹤者將會看到螢幕閃爍為提示。","(内鬼阵营):\n追踪者可以追踪其他人,追踪者可以变形为某个人以切换追踪目标为变形的目标。玩家名称下面的箭头代表着目标的方向。当内鬼队友杀人时,追踪者将会看到击杀闪烁提示。" "EvilGuesserInfoLong","(内鬼阵营):\n邪恶赌怪可以在会议时猜测某位玩家的职业,正确则击杀目标,错误则会自杀。\n猜测指令为:/bt [玩家编号] [职业名]\n您可以在玩家名字前看到该玩家的编号,或者使用/id指令查看所有玩家的编号。","(Impostors):\nThe Evil Guesser can guess the role of a certain player during the meeting. If it is correct, the target dies, and if it is wrong, the Evil Guesser dies.\nThe guessing command is: /bt [player id] [role]\nYou can see the player's id before the player's name, or use the /id command to view the id of all players."," (Предатель):\nЗлой Угадыватель может угадывать роли определённого игрока во время встречи. Если он угадает роль правильно, то он убьет эту цель, а если неправильно, то он совершит самоубийство. \nКоманда для угадываний: '/bt [Номер игрока] [Название Роли]'' \nПример: /bt 3 Байт \nВы можете увидеть номер игрока перед его никнеймом, или же для просмотра номеров всех игроков нужно использовать команду ''/id''.","(偽裝者陣營):\n邪惡賭怪可以在會議上猜測某位玩家的職業,正確則會讓猜測目標死亡,錯誤則會自殺,\n猜測指令為/bt [玩家ID] [職業名](指令開頭的/bt可以替換為/bet、/guess、/gs等)\n你可以在玩家名字前看到玩家ID,或使用/id來查詢所有玩家的ID。","(内鬼阵营):\n邪恶赌怪可以在会议时猜测某位玩家的职业,正确则击杀目标,错误则会自杀。\n猜测指令为:/bt [玩家编号] [职业名]\n您可以在玩家名字前看到该玩家的编号,或者使用/id指令查看所有玩家的编号。" -"AntiAdminerInfoLong","(内鬼阵营):\n监管者可以随时知道是否有船员阵营玩家或中立阵营玩家靠近监控面板、管理室地图、生命检测、通行记录等设备。请注意:监管者并不知道靠近的人是否真的在使用设备,只是知道有人靠近设备。","(Impostors):\nThe Disruptor can at any time find out if there are crewmates or neutrals near Cameras, Admin Table, Vitals, DoorLog and/or other devices. Note: Disruptor does not know for sure if the player is using the device while near it, they only know that someone is near the device."," (Предатель):\nАнти Админер может в любое время узнать, есть ли Члены Экипажа или Нейтральные игроки рядом с Камерами, Админским столом, Пульсами, Журналами и с другими устройствами. \nПожалуйста, обратите внимание: Анти Админер не знает наверняка использует ли игрок устройство находясь рядом с ним, а знает только то, что кто-то находится рядом с устройством.","(偽裝者陣營):\n監管者在有非偽裝者陣營玩家靠近任何一個設備時(例如管理室地圖、心電圖、通行紀錄等) 會收到提示,但是請注意: 監管者只知道有人在靠近此設備,並不知道是否在真正使用該設備。","(内鬼阵营):\n监管者可以随时知道是否有船员阵营玩家或中立阵营玩家靠近监控面板、管理室地图、生命检测、通行记录等设备。请注意:监管者并不知道靠近的人是否真的在使用设备,只是知道有人靠近设备。" +"AntiAdminerInfoLong","(内鬼阵营):\n监管者可以随时知道是否有船员阵营玩家或中立阵营玩家靠近监控面板、管理室地图、生命检测、通行记录等设备。请注意:监管者并不知道靠近的人是否真的在使用设备,只是知道有人靠近设备。","(Impostors):\nThe Anti Adminer can at any time find out if there are crewmates or neutrals near Cameras, Admin Table, Vitals, DoorLog and/or other devices. Note: Anti Adminer does not know for sure if the player is using the device while near it, they only know that someone is near the device."," (Предатель):\nАнти Админер может в любое время узнать, есть ли Члены Экипажа или Нейтральные игроки рядом с Камерами, Админским столом, Пульсами, Журналами и с другими устройствами. \nПожалуйста, обратите внимание: Анти Админер не знает наверняка использует ли игрок устройство находясь рядом с ним, а знает только то, что кто-то находится рядом с устройством.","(偽裝者陣營):\n監管者在有非偽裝者陣營玩家靠近任何一個設備時(例如管理室地圖、心電圖、通行紀錄等) 會收到提示,但是請注意: 監管者只知道有人在靠近此設備,並不知道是否在真正使用該設備。","(内鬼阵营):\n监管者可以随时知道是否有船员阵营玩家或中立阵营玩家靠近监控面板、管理室地图、生命检测、通行记录等设备。请注意:监管者并不知道靠近的人是否真的在使用设备,只是知道有人靠近设备。" "SansInfoLong","(内鬼阵营):\n狂妄杀手每次成功击杀都会减少他的击杀冷却。","(Impostors):\nThe Arrogance reduces their kill cooldown with each successful kill of theirs."," (Предатель):\nКаждый раз, когда Высокомер совершает убийство, его откат убийства будет уменьшаться. ","(偽裝者陣營):\n狂妄殺手每次殺人都會減少他的殺人冷卻。","(内鬼阵营):\n狂妄杀手每次成功击杀都会减少他的击杀冷却。" "BomberInfoLong","(内鬼阵营):\n自爆兵可以使用变形按钮来进行自爆,炸死一定范围里的玩家。但是作为代价,自爆兵自己也会被炸死。请注意:自爆兵爆炸的时候全体玩家会看到杀戮闪烁。","(Impostors):\nThe Bomber can use the shapeshift/pet button to self-explode, killing players within a certain range. But as a price, the Bomber will also die. Note: All players will see a kill-flash when the Bomber explodes."," (Предатель):\nБомбер может использовать Морф, чтобы взорвать игроков которые оказались в радиусе бомбы. Но в качестве платы, сам Бомбер будет также взорван. \nПожалуйста, обратите внимание: Когда Бомбер взорвётся, все игроки увидят ''Вспышку Убийства''. Эта вспышка точно такая же, как вспышка убийства когда умирает Знаменитость. Пожалуйста, обращайте внимание на экран.","(偽裝者陣營):\n自爆兵能使用變形來炸死一定範圍內的玩家,但是作為代價,自爆兵自己也會被炸死。請注意: 自爆兵爆炸時全部玩家會看到螢幕閃爍作為提示(這個閃爍是跟網紅一樣的,請注意區別)。","(内鬼阵营):\n自爆兵可以使用变形按钮来进行自爆,炸死一定范围里的玩家。但是作为代价,自爆兵自己也会被炸死。请注意:自爆兵爆炸的时候全体玩家会看到杀戮闪烁。" "ScavengerInfoLong","(内鬼阵营):\n清道夫击杀不会留下尸体。此外若受害者为诱饵,则诱饵的技能不会发动。","(Impostors):\nScavenger kills do not leave dead bodies behind. In addition, if the victim is a bait, no self-report will be made."," (Предатель):\nКогда Уборщик убьёт игрока, то зарепортить этот труп будет невозможно.","(偽裝者陣營):\n清道夫在殺人之後不會留下屍體。此外如果受害者為誘餌,則清道夫不會報告誘餌的屍體。","(内鬼阵营):\n清道夫击杀不会留下尸体。此外若受害者为诱饵,则诱饵的技能不会发动。" @@ -2407,12 +2407,12 @@ "Fortune Teller V3" "DivinatorCheck.Null","{0}是未列出的身份\n此消息不应正常显示","{0} is a role that is not listed.\nThis message should not appear normally.","","","" "DivinatorCheck.Result0","{0}是船员、是工程师、科学家、内鬼或变形者其中之一","{0} is either Crewmate, Engineer, Scientist, Impostor, or Shapeshifter","","","" -"DivinatorCheck.Result1","{0}是失忆者、模仿者、抹除者、逃亡者、监管者、眩晕者或掷弹兵其中之一","{0} is either Amnesiac, Copycat, Eraser, Telecommunication, Disruptor, Dazzler, Lighter, or Grenadier","","","" +"DivinatorCheck.Result1","{0}是失忆者、模仿者、抹除者、逃亡者、监管者、眩晕者或掷弹兵其中之一","{0} is either Amnesiac, Copycat, Eraser, Telecommunication, Anti Adminer, Dazzler, Lighter, or Grenadier","","","" "DivinatorCheck.Result2","{0}是十字军、预言家、纵火犯、刺客、球状闪电或集票者其中之一","{0} is either Crusader, Investigator, Arsonist, Ninja, Undertaker, Lightning, or Collector","","","" "DivinatorCheck.Result3","{0}是资本家、赝品商、贪婪者、商人或魔术师其中之一","{0} is either Capitalist, Witness, Ventguard, Greedy, Merchant, or Trickster","","","" "DivinatorCheck.Result4","{0}是瘟疫使者、瘟疫、观察者、嗜血骑士、守护者或饥荒其中之一","{0} is either Pestilence, Plaguebearer, Observer, Blood Knight, Guardian, or Wildling","","","" "DivinatorCheck.Result5","{0}是吟游诗人、天启、遐想者、狂妄杀手、杀戳机器或肢解者其中之一","{0} is either Bard, Ricochet, Juggernaut, Security Guard, Arrogance, Killing Machine, or Butcher","","","" -"DivinatorCheck.Result6","{0}是验尸官、邪恶追踪者、验尸官、寻迹者或正义追踪者其中之一","{0} is either Coroner, Agent, Mortician, Tracefinder, Romantic, or Tracker","","","" +"DivinatorCheck.Result6","{0}是验尸官、邪恶追踪者、验尸官、寻迹者或正义追踪者其中之一","{0} is either Coroner, Evil Tracker, Mortician, Tracefinder, Romantic, or Tracker","","","" "DivinatorCheck.Result7","{0}是保镖、自爆兵、烟花商人或核武器其中之一","{0} is either Bodyguard, Bomber, Lookout, Vengeful Romantic, Ruthless Romantic, Fireworker, or Nuker","","","" "DivinatorCheck.Result8","{0}是赏金猎人、侦探、FFF团、清理工、美杜莎或愚者其中之一","{0} is either Bounty Hunter, Detective, Hater, Cleaner, Medusa, or Psychic","","","" "DivinatorCheck.Result9","{0}是罪犯、处刑者、律师、告密者、分散者或法医其中之一","{0} is either Convict, Executioner, Lawyer, Snitch, Disperser, or Doctor","","","" @@ -2431,8 +2431,8 @@ "DivinatorCheck.Result22","{0}是诡雷、快枪手、连环杀手、警长、仰慕者或术士其中之一","{0} is either Trapster, Quick Shooter, Serial Killer, Sheriff, Werewolf, Admirer, or Warlock","","","" "DivinatorCheck.Result23","{0}是调查员、军师、祭祀者、巫师或女巫其中之一","{0} is either Fortune Teller, Consigliere, Ritualist, Imitator, Hex Master, or Witch","","","" "DivinatorCheck.Result24","{0}是懒人、跟随者、鹈鹕、清道夫或秃鹫其中之一","{0} is either Lazy Guy, Hacker, Follower, Pelican, Vengeance, Scavenger, or Vulture","","","" -"DivinatorCheck.Result25","{0}是扫把星、骑士、老兵或刽子手其中之一","{0} is either Jinx, Vigilante, Veteran, Task Manager, Pyromaniac, or Hangman","","","" -"DivinatorCheck.Result26","{0}是通灵师、灵魂召唤师、灵魂论者、寄生虫、隐匿者或魅影其中之一","{0} is either Medium, Spiritcaller, Spiritualist, Parasite, Swooper, or Wraith","","","" +"DivinatorCheck.Result25","{0}是扫把星、骑士、老兵或刽子手其中之一","{0} is either Jinx, Vigilante, Veteran, Enigma, Task Manager, Pyromaniac, or Hangman","","","" +"DivinatorCheck.Result26","{0}是通灵师、灵魂召唤师、灵魂论者、寄生虫、隐匿者或魅影其中之一","{0} is either Medium, Camera Man, Spiritcaller, Spiritualist, Parasite, Swooper, or Wraith","","","" "DivinatorCheck.Result27","{0}可能是时间操控者, 时间之主, 蚀时者, 千面鬼, 或者狙击手其中之一","{0} is either Time Manager, Time Master, Time Thief, Tether, Shapemaster, or Sniper" "DivinatorCheck.Result28","{0}可能是傀儡师, 巫婆, 捕快, 传送师, 龙卷风, 或者嗜血杀手其中之一","{0} is either Puppeteer, Deputy, Aid, Transporter, Twister, Mercenary","","","" "DivinatorCheck.Result29","{0}可能是船鬼, 展现者, 工作狂, 幻影, 或者恐怖分子其中之一","{0} is either Crewpostor, Marshall, Workaholic, Phantom, Speedrunner, or Terrorist","","","" @@ -2505,6 +2505,69 @@ "VentguardBlockDoesNotAffectCrew","","Crewmates can use blocked vents","","","" "VentBlockSuccess","","This vent is now blocked","","","" +"## Enigma" +"Enigma","","Enigma","","","" +"EnigmaInfo","","Get Clues about Killers","","","" +"EnigmaInfoLong","","(Crewmates):\nAs the Enigma, you get a random clue about the killer each meeting, depending on the setting, you may have to report the body to receive a clue. The more tasks you complete the preciser the clues get.","","","" +"EnigmaClueStage1Tasks","","Number of Tasks to complete to see Stage 1 Clues","","","" +"EnigmaClueStage2Tasks","","Number of Tasks to complete to see Stage 2 Clues","","","" +"EnigmaClueStage3Tasks","","Number of Tasks to complete to see Stage 3 Clues","","","" +"EnigmaClueStage2Probability","","Probability to see Stage 2 Clues","","","" +"EnigmaClueStage3Probability","","Probability to see Stage 3 Clues","","","" +"EnigmaClueGetCluesWithoutReporting","","Enigma can get Clues without reporting a dead body","","","" +"EnigmaClueHat1","","The Killer wears a Hat!","","","" +"EnigmaClueHat2","","The Killer does not wear a Hat!","","","" +"EnigmaClueHat3","","The Killer wears {0} as a Hat!","","","" +"EnigmaClueSkin1","","The Killer wears a Skin!","","","" +"EnigmaClueSkin2","","The Killer does not wear a Skin!","","","" +"EnigmaClueSkin3","","The Killer wears {0} as a Skin!","","","" +"EnigmaClueVisor1","","The Killer wears a Visor!","","","" +"EnigmaClueVisor2","","The Killer does not wear a Visor!","","","" +"EnigmaClueVisor3","","The Killer wears {0} as a Visor!","","","" +"EnigmaCluePet1","","The Killer does have a Pet!","","","" +"EnigmaCluePet2","","The Killer does not have a Pet!","","","" +"EnigmaCluePet3","","The Killer has {0} as a Pet!","","","" +"EnigmaClueName1","","The Name of the Killer contains the letter {0} or the letter {1}!","","","" +"EnigmaClueName2","","The Name of the Killer contains the letter {0}!","","","" +"EnigmaClueName3","","The Name of the Killer contains the letter {0} and the letter {1}!","","","" +"EnigmaClueNameLength1","","The Name of the Killer has a Length between {0} and {1} letters!","","","" +"EnigmaClueNameLength2","","The Name of the Killer has a Length of {0} letters!","","","" +"EnigmaClueColor1","","The Killer has a light color!","","","" +"EnigmaClueColor2","","The Killer has a dark color!","","","" +"EnigmaClueColor3","","The Killer's color is {0}!","","","" +"EnigmaClueLocation","","The Last Room the Killer was in is {0}!","","","" +"EnigmaClueStatus1","","The Killer is currently inside a Vent!","","","" +"EnigmaClueStatus2","","The Killer is currently on a Ladder!","","","" +"EnigmaClueStatus3","","The Killer is already Dead!","","","" +"EnigmaClueStatus4","","The Killer is still Alive!","","","" +"EnigmaClueRole1","","The Killer is an Impostor!","","","" +"EnigmaClueRole2","","The Killer is a Neutral!","","","" +"EnigmaClueRole3","","The Killer is a Crewmate!","","","" +"EnigmaClueRole4","","The Killer's Role is {0}!","","","" +"EnigmaClueLevel1","","The Killer's Level is above 50!","","","" +"EnigmaClueLevel2","","The Killer's Level is below 50!","","","" +"EnigmaClueLevel3","","The Killer's Level is between {0} and {1}!","","","" +"EnigmaClueLevel4","","The Killer's Level is {0}!","","","" +"EnigmaClueFriendCode","","The Killer's Friendcode is {0}!","","","" +"EnigmaClueHatTitle","","Enigma Hat Clue!","","","" +"EnigmaClueVisorTitle","","Enigma Visor Clue!","","","" +"EnigmaClueSkinTitle","","Enigma Skin Clue!","","","" +"EnigmaCluePetTitle","","Enigma Pet Clue!","","","" +"EnigmaClueNameTitle","","Enigma Name Clue!","","","" +"EnigmaClueNameLengthTitle","","Enigma Name lenght Clue!","","","" +"EnigmaClueColorTitle","","Enigma Color Clue!","","","" +"EnigmaClueLocationTitle","","Enigma Location Clue!","","","" +"EnigmaClueStatusTitle","","Enigma Status Clue!","","","" +"EnigmaClueRoleTitle","","Enigma Role Clue!","","","" +"EnigmaClueLevelTitle","","Enigma Level Clue!","","","" +"EnigmaClueFriendCodeTitle","","Enigma Friendcode Clue!","","","" +"EnigmaClueTitle","","Enigma Clue!","","","" + +"## Camera Man" +"CameraMan","","Camera Man","","","" +"CameraManInfo","","View Cameras anytime","","","" +"CameraManInfoLong","","(Crewmates):\nAs the Camera Man, you can vent/pet to instantly teleport to the security room.","","","" + "## Hacker" "NiceHacker","","Hacker","","","" "NiceHackerInfo","","Watch Admin Table from anywhere","","","" @@ -2715,7 +2778,7 @@ "## Lobby Games" "GNoCommandInfo","","This Command can only be used when in lobby or after you die.\n\ntype /gno X to play guess a number. X can be a number between 0 and 99 (both included). \n\nYou get maximum of 7 tries to guess the number.\n\n Example:- /gno 10","","","" -"GNoLost","","Oh, you were so close! Just one more guess, and you might have cracked the Da Vinci code! By the way, the secret number was... {0}! But hey, you were only off by a few billion possibilities. Better luck next time, Sherlock! ","","","" +"GNoLost","","Oh, you were so close! Just one more guess, and you might have deciphered the Da Vinci code! By the way, the secret number was... {0}! But hey, you were only off by a few billion possibilities. Better luck next time, Sherlock! ","","","" "GNoLow","","Oh, you're really nailing this! It's so low, I almost need a shovel to dig it up!\nYou have {0} guesses left!","","","" "GNoHigh","","Oh, absolutely! You're getting warmer. In fact, it's so high, I need a telescope to see it from here! \nYou have {0} guesses left!","","","" "GNoWon","","Oh, how did you ever figure that out? It's almost like you're a mind reader! Congratulations, you're a genius! You found the secret number in {0} guesses left!","","","" diff --git a/Roles/Crewmate/CameraMan.cs b/Roles/Crewmate/CameraMan.cs new file mode 100644 index 000000000..365e90207 --- /dev/null +++ b/Roles/Crewmate/CameraMan.cs @@ -0,0 +1,109 @@ +namespace TOHE.Roles.Crewmate +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using UnityEngine; + using static TOHE.Options; + using static TOHE.Utils; + + public static class CameraMan + { + private static readonly int Id = 640000; + private static List playerIdList = new(); + public static Dictionary UseLimit = new(); + + public static OptionItem VentCooldown; + public static OptionItem UseLimitOpt; + public static OptionItem CameraManAbilityUseGainWithEachTaskCompleted; + + public static void SetupCustomOption() + { + 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]) + .SetValueFormat(OptionFormat.Times); + CameraManAbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(Id + 12, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.1f), 1f, TabGroup.CrewmateRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.CameraMan]) + .SetValueFormat(OptionFormat.Times); + } + public static void Init() + { + playerIdList = new(); + UseLimit = new(); + } + public static void Add(byte playerId) + { + playerIdList.Add(playerId); + UseLimit.Add(playerId, UseLimitOpt.GetInt()); + } + public static bool IsEnable => playerIdList.Any(); + public static void OnEnterVent(PlayerControl pc) + { + if (pc == null) return; + if (!pc.Is(CustomRoles.CameraMan)) return; + + if (UseLimit[pc.PlayerId] >= 1) + { + UseLimit[pc.PlayerId] -= 1; + Main.CameraManCD.TryAdd(pc.PlayerId, GetTimeStamp()); + + Vector2 pos; + + switch (Main.NormalOptions.MapId) + { + 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; + default: + TOHE.Logger.Error("Invalid MapID", "CameraMan Teleport"); + return; + } + + _ = new LateTask(() => { TP(pc.NetTransform, pos); }, UsePets.GetBool() ? 0.1f : 2f, "CameraMan Teleport"); + } + else + { + if (!NameNotifyManager.Notice.ContainsKey(pc.PlayerId)) pc.Notify(Translator.GetString("OutOfAbilityUsesDoMoreTasks")); + } + } + public static string GetProgressText(byte playerId, bool comms) + { + var sb = new StringBuilder(); + + var taskState = Main.PlayerStates?[playerId].GetTaskState(); + Color TextColor; + var TaskCompleteColor = Color.green; + var NonCompleteColor = Color.yellow; + var NormalColor = taskState.IsTaskFinished ? TaskCompleteColor : NonCompleteColor; + TextColor = comms ? Color.gray : NormalColor; + string Completed = comms ? "?" : $"{taskState.CompletedTasksCount}"; + + Color TextColor1; + if (UseLimit[playerId] < 1) TextColor1 = Color.red; + else TextColor1 = Color.white; + + sb.Append(ColorString(TextColor, $"- {Completed}/{taskState.AllTasksCount}")); + sb.Append(ColorString(TextColor1, $" - {Math.Round(UseLimit[playerId], 1)}")); + + return sb.ToString(); + } + public static string GetHudText(PlayerControl pc) + { + return !UsePets.GetBool() || !Main.CameraManCD.TryGetValue(pc.PlayerId, out var cd) + ? string.Empty + : string.Format(Translator.GetString("CDPT"), VentCooldown.GetInt() - (GetTimeStamp() - cd) + 1); + } + } +} \ No newline at end of file diff --git a/Roles/Crewmate/Divinator.cs b/Roles/Crewmate/Divinator.cs index 795bd5107..e80b5d360 100644 --- a/Roles/Crewmate/Divinator.cs +++ b/Roles/Crewmate/Divinator.cs @@ -295,6 +295,7 @@ public static class Divinator CustomRoles.Jinx or CustomRoles.SwordsMan or CustomRoles.Veteran or + CustomRoles.Enigma or CustomRoles.TaskManager or CustomRoles.Pyromaniac or CustomRoles.Hangman @@ -304,6 +305,7 @@ public static class Divinator CustomRoles.Spiritcaller or CustomRoles.Spiritualist or CustomRoles.Parasite or + CustomRoles.CameraMan or CustomRoles.Swooper or CustomRoles.Wraith => "Result26", diff --git a/Roles/Crewmate/Enigma.cs b/Roles/Crewmate/Enigma.cs new file mode 100644 index 000000000..123a8c5a4 --- /dev/null +++ b/Roles/Crewmate/Enigma.cs @@ -0,0 +1,522 @@ +using System.Collections.Generic; +using System.Linq; +using static TOHE.Options; +using static TOHE.Translator; + +namespace TOHE.Roles.Crewmate +{ + public class Enigma + { + private static readonly int Id = 8460; + private static List playerIdList = new(); + private static Dictionary> ShownClues = new(); + + public static OptionItem EnigmaClueStage1Tasks; + public static OptionItem EnigmaClueStage2Tasks; + public static OptionItem EnigmaClueStage3Tasks; + public static OptionItem EnigmaClueStage2Probability; + public static OptionItem EnigmaClueStage3Probability; + public static OptionItem EnigmaGetCluesWithoutReporting; + + public static Dictionary MsgToSend = new(); + public static Dictionary MsgToSendTitle = new(); + + private static readonly List EnigmaClues = new() + { + new EnigmaHatClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.HatClue }, + new EnigmaHatClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.HatClue }, + new EnigmaVisorClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.VisorClue }, + new EnigmaVisorClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.VisorClue }, + new EnigmaSkinClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.SkinClue }, + new EnigmaSkinClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.SkinClue }, + new EnigmaPetClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.PetClue }, + new EnigmaPetClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.PetClue }, + new EnigmaNameClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.NameClue }, + new EnigmaNameClue { ClueStage = 2, EnigmaClueType = EnigmaClueType.NameClue }, + new EnigmaNameClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.NameClue }, + new EnigmaNameLengthClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.NameLengthClue }, + new EnigmaNameLengthClue { ClueStage = 2, EnigmaClueType = EnigmaClueType.NameLengthClue }, + new EnigmaNameLengthClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.NameLengthClue }, + new EnigmaColorClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.ColorClue }, + new EnigmaColorClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.ColorClue }, + new EnigmaLocationClue { ClueStage = 2, EnigmaClueType = EnigmaClueType.LocationClue }, + new EnigmaKillerStatusClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.KillerStatusClue }, + new EnigmaKillerRoleClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.KillerRoleClue }, + new EnigmaKillerRoleClue { ClueStage = 2, EnigmaClueType = EnigmaClueType.KillerRoleClue }, + new EnigmaKillerLevelClue { ClueStage = 1, EnigmaClueType = EnigmaClueType.KillerLevelClue }, + new EnigmaKillerLevelClue { ClueStage = 2, EnigmaClueType = EnigmaClueType.KillerLevelClue }, + new EnigmaKillerLevelClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.KillerLevelClue }, + new EnigmaFriendCodeClue { ClueStage = 3, EnigmaClueType = EnigmaClueType.FriendCodeClue }, + }; + + public static void SetupCustomOption() + { + SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Enigma); + EnigmaClueStage1Tasks = FloatOptionItem.Create(Id + 11, "EnigmaClueStage1Tasks", new(0f, 10f, 1f), 1f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Enigma]) + .SetValueFormat(OptionFormat.Times); + EnigmaClueStage2Tasks = FloatOptionItem.Create(Id + 12, "EnigmaClueStage2Tasks", new(0f, 10f, 1f), 3f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Enigma]) + .SetValueFormat(OptionFormat.Times); + EnigmaClueStage3Tasks = FloatOptionItem.Create(Id + 13, "EnigmaClueStage3Tasks", new(0f, 10f, 1f), 7f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Enigma]) + .SetValueFormat(OptionFormat.Times); + EnigmaClueStage2Probability = IntegerOptionItem.Create(Id + 14, "EnigmaClueStage2Probability", new(0, 100, 5), 75, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Enigma]) + .SetValueFormat(OptionFormat.Percent); + EnigmaClueStage3Probability = IntegerOptionItem.Create(Id + 15, "EnigmaClueStage3Probability", new(0, 100, 5), 60, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Enigma]) + .SetValueFormat(OptionFormat.Percent); + EnigmaGetCluesWithoutReporting = BooleanOptionItem.Create(Id + 16, "EnigmaClueGetCluesWithoutReporting", true, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Enigma]); + + OverrideTasksData.Create(Id + 20, TabGroup.CrewmateRoles, CustomRoles.Enigma); + } + public static void Init() + { + playerIdList = new(); + ShownClues = new(); + MsgToSend = new(); + MsgToSendTitle = new(); + } + public static void Add(byte playerId) + { + playerIdList.Add(playerId); + ShownClues.Add(playerId, new List()); + } + public static bool IsEnable => playerIdList.Count > 0; + + public static void OnReportDeadBody(PlayerControl player, GameData.PlayerInfo targetInfo) + { + if (targetInfo == null) return; + + var target = Utils.GetPlayerById(targetInfo.PlayerId); + if (target == null) return; + + PlayerControl killer = target.GetRealKiller(); + if (killer == null) return; + + string title; + string msg; + var rd = IRandom.Instance; + + foreach (var playerId in playerIdList) + { + if (!EnigmaGetCluesWithoutReporting.GetBool() && playerId != player.PlayerId) continue; + + var enigmaPlayer = Utils.GetPlayerById(playerId); + if (enigmaPlayer == null) continue; + + int tasksCompleted = enigmaPlayer.GetPlayerTaskState().CompletedTasksCount; + int stage = 0; + bool showStageClue = false; + + if (tasksCompleted >= EnigmaClueStage3Tasks.GetInt()) + { + stage = 3; + showStageClue = rd.Next(0, 100) < EnigmaClueStage3Probability.GetInt(); + } + else if (tasksCompleted >= EnigmaClueStage2Tasks.GetInt()) + { + stage = 2; + showStageClue = rd.Next(0, 100) < EnigmaClueStage2Probability.GetInt(); + } + else if (tasksCompleted >= EnigmaClueStage1Tasks.GetInt()) + stage = 1; + + var clues = EnigmaClues.Where(a => a.ClueStage <= stage && + !ShownClues[playerId].Any(b => b.EnigmaClueType == a.EnigmaClueType && b.ClueStage == a.ClueStage)) + .ToList(); + if (clues.Count == 0) continue; + if (showStageClue && clues.Any(a => a.ClueStage == stage)) + clues = clues.Where(a => a.ClueStage == stage).ToList(); + + EnigmaClue clue = clues[rd.Next(0, clues.Count - 1)]; + title = clue.Title; + msg = clue.GetMessage(killer, showStageClue); + + ShownClues[playerId].Add(clue); + + if (MsgToSend.ContainsKey(playerId)) + MsgToSend[playerId] = msg; + else + MsgToSend.Add(playerId, msg); + + if (MsgToSendTitle.ContainsKey(playerId)) + MsgToSendTitle[playerId] = title; + else + MsgToSendTitle.Add(playerId, title); + } + } + + private abstract class EnigmaClue + { + public int ClueStage { get; set; } + public EnigmaClueType EnigmaClueType { get; set; } + + public abstract string Title { get; } + public abstract string GetMessage(PlayerControl killer, bool showStageClue); + } + private class EnigmaHatClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueHatTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + var killerOutfit = Camouflage.PlayerSkins[killer.PlayerId]; + if (killerOutfit.HatId == "hat_EmptyHat") + return GetString("EnigmaClueHat2"); + + switch (this.ClueStage) + { + case 1: + case 2: + return GetString("EnigmaClueHat1"); + case 3: + if (showStageClue) + return string.Format(GetString("EnigmaClueHat3"), killerOutfit.HatId); + return GetString("EnigmaClueHat1"); + } + + return null; + } + } + private class EnigmaVisorClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueVisorTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + var killerOutfit = Camouflage.PlayerSkins[killer.PlayerId]; + if (killerOutfit.VisorId == "visor_EmptyVisor") + return GetString("EnigmaClueVisor2"); + + switch (this.ClueStage) + { + case 1: + case 2: + return GetString("EnigmaClueVisor1"); + case 3: + if (showStageClue) + return string.Format(GetString("EnigmaClueVisor3"), killerOutfit.VisorId); + return GetString("EnigmaClueVisor1"); + } + + return null; + } + } + private class EnigmaSkinClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueSkinTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + var killerOutfit = Camouflage.PlayerSkins[killer.PlayerId]; + if (killerOutfit.SkinId == "skin_EmptySkin") + return GetString("EnigmaClueSkin2"); + + switch (this.ClueStage) + { + case 1: + case 2: + return GetString("EnigmaClueSkin1"); + case 3: + if (showStageClue) + return string.Format(GetString("EnigmaClueSkin3"), killerOutfit.SkinId); + return GetString("EnigmaClueSkin1"); + } + + return null; + } + } + private class EnigmaPetClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaCluePetTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + var killerOutfit = Camouflage.PlayerSkins[killer.PlayerId]; + if (killerOutfit.PetId == "pet_EmptyPet") + return GetString("EnigmaCluePet2"); + + switch (this.ClueStage) + { + case 1: + case 2: + return GetString("EnigmaCluePet1"); + case 3: + if (showStageClue) + return string.Format(GetString("EnigmaCluePet3"), killerOutfit.PetId); + return GetString("EnigmaCluePet1"); + } + + return null; + } + } + private class EnigmaNameClue : EnigmaClue + { + private readonly IRandom rd = IRandom.Instance; + + public override string Title { get { return GetString("EnigmaClueNameTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + string killerName = killer.GetRealName(); + string letter = killerName[rd.Next(0, killerName.Length - 1)].ToString().ToLower(); + + switch (this.ClueStage) + { + case 1: + return GetStage1Clue(killer, letter); + case 2: + if (showStageClue) GetStage2Clue(letter); + return GetStage1Clue(killer, letter); + case 3: + if (showStageClue) GetStage3Clue(killerName, letter); + if (rd.Next(0, 100) < EnigmaClueStage2Probability.GetInt()) GetStage2Clue(letter); + return GetStage1Clue(killer, letter); + } + + return null; + } + + private string GetStage1Clue(PlayerControl killer, string letter) + { + string randomLetter = GetRandomLetter(killer, letter); + int random = rd.Next(1, 2); + if (random == 1) + return string.Format(GetString("EnigmaClueName1"), letter, randomLetter); + else + return string.Format(GetString("EnigmaClueName1"), randomLetter, letter); + } + + private static string GetStage2Clue(string letter) + { + return string.Format(GetString("EnigmaClueName2"), letter); + } + + private string GetStage3Clue(string killerName, string letter) + { + string letter2 = string.Empty; + string tmpName = killerName.Replace(letter, string.Empty); + if (!string.IsNullOrEmpty(tmpName)) + { + letter2 = tmpName[rd.Next(0, tmpName.Length - 1)].ToString().ToLower(); + } + + return string.Format(GetString("EnigmaClueName3"), letter, letter2); + } + + private string GetRandomLetter(PlayerControl killer, string letter) + { + var alivePlayers = Main.AllAlivePlayerControls.Where(a => a.PlayerId != killer.PlayerId).ToList(); + var rndPlayer = alivePlayers[rd.Next(0, alivePlayers.Count - 1)]; + string rndPlayerName = rndPlayer.GetRealName().Replace(letter, ""); + string letter2 = rndPlayerName[rd.Next(0, rndPlayerName.Length - 1)].ToString().ToLower(); + return letter2; + } + } + private class EnigmaNameLengthClue : EnigmaClue + { + private readonly IRandom rd = IRandom.Instance; + + public override string Title { get { return GetString("EnigmaClueNameLengthTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + int length = killer.GetRealName().Length; + + switch (this.ClueStage) + { + case 1: + return GetStage1Clue(length); + case 2: + if (showStageClue) return GetStage2Clue(length); + return GetStage1Clue(length); + case 3: + if (showStageClue) return GetStage3Clue(length); + if (rd.Next(0, 100) < EnigmaClueStage2Probability.GetInt()) return GetStage2Clue(length); + return GetStage1Clue(length); + } + + return null; + } + + private string GetStage1Clue(int length) + { + int start = length - rd.Next(2, 3); + int end = length + rd.Next(2, 3); + + start = start < 0 ? 0 : start; + end = end > 8 ? 8 : end; + + return string.Format(GetString("EnigmaClueNameLength1"), start, end); + } + + private string GetStage2Clue(int length) + { + int start = length - rd.Next(1, 2); + int end = length + rd.Next(1, 2); + + start = start < 0 ? 0 : start; + end = end > 8 ? 8 : end; + + return string.Format(GetString("EnigmaClueNameLength1"), start, end); + } + + private static string GetStage3Clue(int length) + { + return string.Format(GetString("EnigmaClueNameLength2"), length); + } + } + private class EnigmaColorClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueColorTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + var killerOutfit = Camouflage.PlayerSkins[killer.PlayerId]; + + switch (this.ClueStage) + { + case 1: + case 2: + return GetStage1Clue(killerOutfit.ColorId); + case 3: + if (showStageClue) return string.Format(GetString("EnigmaClueColor3"), killer.Data.ColorName); + return GetStage1Clue(killerOutfit.ColorId); + } + + return GetStage1Clue(killerOutfit.ColorId); + } + + private static string GetStage1Clue(int colorId) + { + return colorId switch + { + 0 or 3 or 4 or 5 or 7 or 10 or 11 or 13 or 14 or 17 => GetString("EnigmaClueColor1"), + 1 or 2 or 6 or 8 or 9 or 12 or 15 or 16 => GetString("EnigmaClueColor2"), + _ => null, + }; + } + } + private class EnigmaLocationClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueLocationTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + string room = string.Empty; + var targetRoom = Main.PlayerStates[killer.PlayerId].LastRoom; + if (targetRoom == null) room += GetString("FailToTrack"); + else room += GetString(targetRoom.RoomId.ToString()); + return string.Format(GetString("EnigmaClueLocation"), room); + } + } + private class EnigmaKillerStatusClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueStatusTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + if (killer.inVent) + return GetString("EnigmaClueStatus1"); + if (killer.onLadder) + return GetString("EnigmaClueStatus2"); + if (killer.Data.IsDead) + return GetString("EnigmaClueStatus3"); + return GetString("EnigmaClueStatus4"); + } + } + private class EnigmaKillerRoleClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueRoleTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + CustomRoles role = killer.GetCustomRole(); + switch (this.ClueStage) + { + case 1: + if (role.IsImpostor()) return GetString("EnigmaClueRole1"); + if (role.IsNeutral()) return GetString("EnigmaClueRole2"); + return GetString("EnigmaClueRole3"); + case 2: + if (showStageClue) return string.Format(GetString("EnigmaClueRole4"), killer.GetDisplayRoleName()); + if (role.IsImpostor()) return GetString("EnigmaClueRole1"); + if (role.IsNeutral()) return GetString("EnigmaClueRole2"); + return GetString("EnigmaClueRole3"); + } + + return null; + } + } + private class EnigmaKillerLevelClue : EnigmaClue + { + private readonly IRandom rd = IRandom.Instance; + + public override string Title { get { return GetString("EnigmaClueLevelTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + int level = (int)killer.Data.PlayerLevel; + + switch (this.ClueStage) + { + case 1: + return GetStage1Clue(level); + case 2: + if (showStageClue) return GetStage2Clue(level); + return GetStage1Clue(level); + case 3: + if (showStageClue) return GetStage3Clue(level); + if (rd.Next(0, 100) < EnigmaClueStage2Probability.GetInt()) return GetStage2Clue(level); + return GetStage1Clue(level); + } + + return null; + } + + private static string GetStage1Clue(int level) + { + if (level > 50) return GetString("EnigmaClueLevel1"); + return GetString("EnigmaClueLevel2"); + } + + private static string GetStage2Clue(int level) + { + int rangeStart = level - 15; + int rangeEnd = level + 15; + return string.Format(GetString("EnigmaClueLevel3"), rangeStart, rangeEnd >= 100 ? 100 : rangeEnd); + } + + private static string GetStage3Clue(int level) + { + return string.Format(GetString("EnigmaClueLevel4"), level); + } + } + private class EnigmaFriendCodeClue : EnigmaClue + { + public override string Title { get { return GetString("EnigmaClueFriendCodeTitle"); } } + + public override string GetMessage(PlayerControl killer, bool showStageClue) + { + string friendcode = killer.Data.FriendCode; + return string.Format(GetString("EnigmaClueFriendCode"), friendcode); + } + } + + private enum EnigmaClueType + { + HatClue, + VisorClue, + SkinClue, + PetClue, + NameClue, + NameLengthClue, + ColorClue, + LocationClue, + KillerStatusClue, + KillerRoleClue, + KillerLevelClue, + FriendCodeClue + //SecurityClue, + //SabotageClue, + //RandomClue + } + } +} \ No newline at end of file diff --git a/Roles/Crewmate/Farseer.cs b/Roles/Crewmate/Farseer.cs index 968722534..7ac163ceb 100644 --- a/Roles/Crewmate/Farseer.cs +++ b/Roles/Crewmate/Farseer.cs @@ -19,7 +19,7 @@ namespace TOHE.Roles.Crewmate public static OptionItem FarseerRevealTime; public static OptionItem Vision; - private static System.Collections.Generic.List randomRolesForTrickster = new() + private static readonly System.Collections.Generic.List randomRolesForTrickster = new() { CustomRoles.Snitch, CustomRoles.Luckey, @@ -31,6 +31,7 @@ namespace TOHE.Roles.Crewmate CustomRoles.Express, CustomRoles.NiceEraser, CustomRoles.TaskManager, + CustomRoles.CameraMan, CustomRoles.NiceHacker, CustomRoles.Aid, CustomRoles.Tether, diff --git a/Roles/Crewmate/Mediumshiper.cs b/Roles/Crewmate/Mediumshiper.cs index fec05cdd6..f4bcf7b64 100644 --- a/Roles/Crewmate/Mediumshiper.cs +++ b/Roles/Crewmate/Mediumshiper.cs @@ -61,8 +61,8 @@ public static class Mediumshiper if (!CheckCommond(ref msg, "通灵|ms|mediumship|medium", false)) return false; bool ans; - if (msg.Contains("n") || msg.Contains(GetString("No")) || msg.Contains("错") || msg.Contains("不是")) ans = false; - else if (msg.Contains("y") || msg.Contains(GetString("Yes")) || msg.Contains("对")) ans = true; + if (msg.Contains('n') || msg.Contains(GetString("No")) || msg.Contains('错') || msg.Contains("不是")) ans = false; + else if (msg.Contains('y') || msg.Contains(GetString("Yes")) || msg.Contains('对')) ans = true; else { Utils.SendMessage(GetString("MediumshipHelp"), pc.PlayerId); diff --git a/Roles/Crewmate/Tracefinder.cs b/Roles/Crewmate/Tracefinder.cs index bf85e166d..b58707791 100644 --- a/Roles/Crewmate/Tracefinder.cs +++ b/Roles/Crewmate/Tracefinder.cs @@ -67,7 +67,7 @@ public static class Tracefinder else LocateArrow.RemoveAllTarget(playerId); } - public static void OnReportDeadBody(PlayerControl pc, GameData.PlayerInfo target) + public static void OnReportDeadBody(/*PlayerControl pc, GameData.PlayerInfo target*/) { for (int i = 0; i < playerIdList.Count; i++) { diff --git a/Roles/Crewmate/Tracker.cs b/Roles/Crewmate/Tracker.cs index ae9c91796..83f23f7ac 100644 --- a/Roles/Crewmate/Tracker.cs +++ b/Roles/Crewmate/Tracker.cs @@ -111,9 +111,10 @@ namespace TOHE.Roles.Crewmate var targetList = TrackerTarget[seer.PlayerId]; foreach (var trackTarget in targetList) { - if (!TrackerTarget[seer.PlayerId].Contains(trackTarget)) return string.Empty; + if (!TrackerTarget[seer.PlayerId].Contains(trackTarget)) continue; var targetData = Utils.GetPlayerById(trackTarget); + if (targetData == null) continue; var arrow = TargetArrow.GetArrows(seer, trackTarget); arrows += Utils.ColorString(CanGetColoredArrow.GetBool() ? Palette.PlayerColors[targetData.Data.DefaultOutfit.ColorId] : Color.white, arrow); @@ -128,6 +129,7 @@ namespace TOHE.Roles.Crewmate public static string GetArrowAndLastRoom(PlayerControl seer, PlayerControl target) { + if (seer == null || target == null) return string.Empty; string text = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Tracker), TargetArrow.GetArrows(seer, target.PlayerId)); var room = Main.PlayerStates[target.PlayerId].LastRoom; if (room == null) text += Utils.ColorString(Color.gray, "@" + GetString("FailToTrack")); diff --git a/Roles/Impostor/Gangster.cs b/Roles/Impostor/Gangster.cs index e2fffe787..e98b94a70 100644 --- a/Roles/Impostor/Gangster.cs +++ b/Roles/Impostor/Gangster.cs @@ -244,7 +244,6 @@ public static class Gangster pc.Is(CustomRoles.CyberStar) || pc.Is(CustomRoles.Demolitionist) || pc.Is(CustomRoles.NiceEraser) || - pc.Is(CustomRoles.TaskManager) || pc.Is(CustomRoles.Egoist) ); } diff --git a/Roles/Neutral/Lawyer.cs b/Roles/Neutral/Lawyer.cs index 198d79599..81d677a9d 100644 --- a/Roles/Neutral/Lawyer.cs +++ b/Roles/Neutral/Lawyer.cs @@ -169,7 +169,7 @@ public static class Lawyer var GetValue = Target.TryGetValue(seer.PlayerId, out var targetId); return GetValue && targetId == target.PlayerId ? Utils.ColorString(Utils.GetRoleColor(CustomRoles.Lawyer), "§") : string.Empty; } - public static bool CheckExileTarget(GameData.PlayerInfo exiled, bool DecidedWinner, bool Check = false) + public static bool CheckExileTarget(GameData.PlayerInfo exiled/*, bool DecidedWinner, bool Check = false*/) { foreach (var kvp in Target.Where(x => x.Value == exiled.PlayerId)) { diff --git a/Roles/Neutral/Vulture.cs b/Roles/Neutral/Vulture.cs index 71f8b9a4e..6685f9fa7 100644 --- a/Roles/Neutral/Vulture.cs +++ b/Roles/Neutral/Vulture.cs @@ -128,7 +128,6 @@ public static class Vulture var pos = target.GetTruePosition(); float minDis = float.MaxValue; - string minName = string.Empty; foreach (var pc in Main.AllAlivePlayerControls) { if (pc.PlayerId == target.PlayerId) continue; @@ -136,7 +135,7 @@ public static class Vulture if (dis < minDis && dis < 1.5f) { minDis = dis; - minName = pc.GetRealName(); + string minName = pc.GetRealName(); } } diff --git a/main.cs b/main.cs index 5bce5e779..565929602 100644 --- a/main.cs +++ b/main.cs @@ -111,7 +111,8 @@ public class Main : BasePlugin public static Dictionary QuickShooterCD = new(); public static Dictionary DisperserCD = new(); public static Dictionary TwisterCD = new(); - public static GameData.PlayerInfo LastVotedPlayerInfo; + public static Dictionary CameraManCD = new(); + private static GameData.PlayerInfo lastVotedPlayerInfo; public static string LastVotedPlayer; public static List ResetCamPlayerList = new(); public static List winnerList = new(); @@ -249,6 +250,8 @@ public class Main : BasePlugin TName_Snacks_CN[IRandom.Instance.Next(0, TName_Snacks_CN.Count)] : TName_Snacks_EN[IRandom.Instance.Next(0, TName_Snacks_EN.Count)]; + public static GameData.PlayerInfo LastVotedPlayerInfo { get => lastVotedPlayerInfo; set => lastVotedPlayerInfo = value; } + public override void Load() { Instance = this; @@ -380,7 +383,9 @@ public class Main : BasePlugin {CustomRoles.Jailor,"#aa900d"}, {CustomRoles.Monarch, "#FFA500"}, {CustomRoles.Bloodhound, "#8B0000"}, + {CustomRoles.Enigma, "#676798"}, {CustomRoles.Tracker, "#3CB371"}, + {CustomRoles.CameraMan, "#000930"}, {CustomRoles.Merchant, "#D27D2D"}, {CustomRoles.Retributionist, "#228B22"}, {CustomRoles.Monitor, "#7223DA"}, @@ -684,6 +689,7 @@ public enum CustomRoles Express, NiceEraser, TaskManager, + CameraMan, NiceHacker, Spy, Ricochet, @@ -697,6 +703,7 @@ public enum CustomRoles SabotageMaster, Sheriff, Snitch, + Enigma, Marshall, SpeedBooster, Lookout,