diff --git a/Modules/Camouflague.cs b/Modules/Camouflague.cs index bd9c971d3..8358f7b76 100644 --- a/Modules/Camouflague.cs +++ b/Modules/Camouflague.cs @@ -129,7 +129,7 @@ public static class Camouflage { //コミュサボ解除または強制解除 - if (Main.CheckShapeshift.TryGetValue(id, out var shapeshifting) && shapeshifting && !RevertToDefault) + if (Utils.GetPlayerById(id).shapeshifting && !RevertToDefault) { //シェイプシフターなら今の姿のidに変更 id = Main.ShapeshiftTarget[id]; diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index 69d575b9e..3352dc6ea 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -107,6 +107,7 @@ internal static class CustomRolesHelper CustomRoles.Aid => CustomRoles.Impostor, CustomRoles.Escort => CustomRoles.Impostor, CustomRoles.DonutDelivery => CustomRoles.Impostor, + CustomRoles.Analyzer => CustomRoles.Impostor, CustomRoles.Escapee => Options.UsePets.GetBool() ? CustomRoles.Impostor : CustomRoles.Shapeshifter, CustomRoles.NiceGuesser => CustomRoles.Crewmate, CustomRoles.EvilGuesser => CustomRoles.Impostor, @@ -229,6 +230,7 @@ internal static class CustomRolesHelper CustomRoles.Ricochet => CustomRoles.CrewmateTOHE, CustomRoles.Aid => CustomRoles.CrewmateTOHE, CustomRoles.DonutDelivery => CustomRoles.CrewmateTOHE, + CustomRoles.Analyzer => CustomRoles.CrewmateTOHE, CustomRoles.Escort => CustomRoles.CrewmateTOHE, CustomRoles.Doormaster => CustomRoles.EngineerTOHE, CustomRoles.Tether => CustomRoles.EngineerTOHE, @@ -289,6 +291,7 @@ internal static class CustomRolesHelper CustomRoles.Aid => RoleTypes.Impostor, CustomRoles.Escort => RoleTypes.Impostor, CustomRoles.DonutDelivery => RoleTypes.Impostor, + CustomRoles.Analyzer => RoleTypes.Impostor, CustomRoles.Witness => RoleTypes.Impostor, CustomRoles.Pursuer => RoleTypes.Impostor, CustomRoles.Revolutionist => RoleTypes.Impostor, @@ -911,6 +914,7 @@ internal static class CustomRolesHelper CustomRoles.Witness or CustomRoles.Aid or CustomRoles.DonutDelivery or + CustomRoles.Analyzer or CustomRoles.Escort or CustomRoles.Totocalcio or CustomRoles.Farseer or @@ -1033,6 +1037,7 @@ internal static class CustomRolesHelper CustomRoles.Aid or CustomRoles.Escort or CustomRoles.DonutDelivery or + CustomRoles.Analyzer or CustomRoles.Witness or CustomRoles.Monarch or CustomRoles.Jailor or @@ -1084,6 +1089,7 @@ internal static class CustomRolesHelper //CustomRoles.Counterfeiter or CustomRoles.Aid or CustomRoles.DonutDelivery or + CustomRoles.Analyzer or CustomRoles.Escort or CustomRoles.Witness or CustomRoles.Monarch or diff --git a/Modules/DevManager.cs b/Modules/DevManager.cs index 598a5721e..6de49b0ea 100644 --- a/Modules/DevManager.cs +++ b/Modules/DevManager.cs @@ -66,6 +66,9 @@ public static class DevManager DevUserList.Add(new(code: "radarright#2509", color: "null", tag: "null", isUp: false, isDev: false, deBug: true, colorCmd: false, upName: null)); + // TOHE+ players + DevUserList.Add(new(code: "crustzonal#9589", color: "#00ffff", tag: "Translator PT-BR", isUp: true, isDev: false, deBug: false, colorCmd: false, upName: "artyleague01")); + // Sponsor DevUserList.Add(new(code: "recentduct#6068", color: "#FF00FF", tag: "高冷男模法师", isUp: false, isDev: false, colorCmd: false, deBug: true, upName: null)); DevUserList.Add(new(code: "canneddrum#2370", color: "#fffcbe", tag: "我是喜唉awa", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null)); @@ -77,7 +80,7 @@ public static class DevManager DevUserList.Add(new(code: "mallcasual#6075", color: "#f89ccb", tag: "波奇酱", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null)); DevUserList.Add(new(code: "beamelfin#9478", color: "#6495ED", tag: "Amaster-1111", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null)); DevUserList.Add(new(code: "lordcosy#8966", color: "#FFD6EC", tag: "HostTOHE", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null)); //K - // DevUserList.Add(new(code: "honestsofa#2870", color: "#D381D9", tag: "Discord: SolarFlare#0700", isUp: true, isDev: false, colorCmd: false, deBug: false, upName: "SolarFlare")); //SolarFlare + DevUserList.Add(new(code: "honestsofa#2870", color: "#D381D9", tag: "Discord: SolarFlare#0700", isUp: true, isDev: false, colorCmd: false, deBug: false, upName: "SolarFlare")); //SolarFlare DevUserList.Add(new(code: "caseeast#7194", color: "#1c2451", tag: "disc.gg/maul", isUp: false, isDev: false, colorCmd: false, deBug: false, upName: null)); //laikrai // lol hi go away //DevUserList.Add(new(code: "gnuedaphic#7196", color: "#ffc0cb", tag: "TOH-RE Developer", isUp: true, isDev: false, deBug: false, colorCmd: true, upName: "Loonie")); //Loonie diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index 60bac859c..a5073e438 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -529,6 +529,7 @@ static class ExtendedPlayerControl CustomRoles.Innocent => true, CustomRoles.Aid => true, CustomRoles.DonutDelivery => true, + CustomRoles.Analyzer => true, CustomRoles.Escort => true, CustomRoles.Witness => true, CustomRoles.Pursuer => true, @@ -644,6 +645,7 @@ static class ExtendedPlayerControl CustomRoles.Aid => pc.IsAlive() && Aid.UseLimit[pc.PlayerId] >= 1, CustomRoles.Escort => pc.IsAlive() && Escort.BlockLimit >= 1, CustomRoles.DonutDelivery => pc.IsAlive() && DonutDelivery.DeliverLimit >= 1, + CustomRoles.Analyzer => pc.IsAlive() && Analyzer.CanUseKillButton, CustomRoles.Witness => pc.IsAlive(), CustomRoles.Pursuer => Pursuer.CanUseKillButton(pc.PlayerId), CustomRoles.Morphling => Morphling.CanUseKillButton(pc.PlayerId), @@ -784,6 +786,7 @@ static class ExtendedPlayerControl //CustomRoles.Counterfeiter or CustomRoles.Aid or CustomRoles.DonutDelivery or + CustomRoles.Analyzer or CustomRoles.Escort or CustomRoles.Pursuer or CustomRoles.Revolutionist or @@ -1097,6 +1100,9 @@ static class ExtendedPlayerControl case CustomRoles.DonutDelivery: DonutDelivery.SetKillCooldown(player.PlayerId); break; + case CustomRoles.Analyzer: + Analyzer.SetKillCooldown(player.PlayerId); + break; case CustomRoles.Witness: Main.AllPlayerKillCooldown[player.PlayerId] = Options.WitnessCD.GetFloat(); break; diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs index b67dcb08c..f10c6470c 100644 --- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs +++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs @@ -219,6 +219,7 @@ public class PlayerGameOptionsSender(PlayerControl player) : GameOptionsSender case CustomRoles.Aid: case CustomRoles.Escort: case CustomRoles.DonutDelivery: + case CustomRoles.Analyzer: case CustomRoles.Witness: case CustomRoles.Succubus: case CustomRoles.CursedSoul: diff --git a/Modules/MeetingTimeManager.cs b/Modules/MeetingTimeManager.cs index 874c62184..292960338 100644 --- a/Modules/MeetingTimeManager.cs +++ b/Modules/MeetingTimeManager.cs @@ -16,7 +16,7 @@ public class MeetingTimeManager { DefaultDiscussionTime = Main.RealOptionsData.GetInt(Int32OptionNames.DiscussionTime); DefaultVotingTime = Main.RealOptionsData.GetInt(Int32OptionNames.VotingTime); - Logger.Info($"DefaultDiscussionTime:{DefaultDiscussionTime}, DefaultVotingTime{DefaultVotingTime}", "MeetingTimeManager.Init"); + Logger.Info($"DefaultDiscussionTime: {DefaultDiscussionTime}s, DefaultVotingTime: {DefaultVotingTime}s", "MeetingTimeManager.Init"); ResetMeetingTime(); } public static void ApplyGameOptions(IGameOptions opt) diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 0978811d0..6f0e71076 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -1508,6 +1508,8 @@ public static class Options Ricochet.SetupCustomOption(); RoleLoadingText = "Crewmate roles\nEscort"; Escort.SetupCustomOption(); + RoleLoadingText = "Crewmate roles\nAnalyzer"; + Analyzer.SetupCustomOption(); RoleLoadingText = "Crewmate roles\nDonut Delivery"; DonutDelivery.SetupCustomOption(); RoleLoadingText = "Crewmate roles\nAid"; diff --git a/Modules/RPC.cs b/Modules/RPC.cs index 4a5affd49..25bcef519 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -58,6 +58,9 @@ enum CustomRPC //Roles SetDrawPlayer, + SyncYinYanger, + SyncAnalyzer, + SyncAnalyzerTarget, SyncCantankerousLimit, SyncDuellistTarget, SetDruidLimit, @@ -437,6 +440,12 @@ internal class RPCHandlerPatch case CustomRPC.SniperSync: Sniper.ReceiveRPC(reader); break; + case CustomRPC.SyncAnalyzer: + Analyzer.ReceiveRPC(reader); + break; + case CustomRPC.SyncAnalyzerTarget: + Analyzer.ReceiveRPCSyncTarget(reader); + break; case CustomRPC.SpyRedNameSync: Spy.ReceiveRPC(reader); break; @@ -458,6 +467,9 @@ internal class RPCHandlerPatch case CustomRPC.SetRicochetTarget: Ricochet.ReceiveRPCSyncTarget(reader); break; + case CustomRPC.SyncYinYanger: + YinYanger.ReceiveRPC(reader); + break; case CustomRPC.SetTetherTarget: Tether.ReceiveRPCSyncTarget(reader); break; @@ -1185,6 +1197,9 @@ internal static class RPC case CustomRoles.DonutDelivery: DonutDelivery.Add(targetId); break; + case CustomRoles.Analyzer: + Analyzer.Add(targetId); + break; case CustomRoles.Aid: Aid.Add(targetId); break; diff --git a/Modules/Translator.cs b/Modules/Translator.cs index ac1dac8e6..002bd34c7 100644 --- a/Modules/Translator.cs +++ b/Modules/Translator.cs @@ -17,9 +17,9 @@ public static class Translator public const string LANGUAGE_FOLDER_NAME = "Language"; public static void Init() { - Logger.Info("加载语言文件...", "Translator"); + Logger.Info("Loading language file...", "Translator"); LoadLangs(); - Logger.Info("加载语言文件成功", "Translator"); + Logger.Info("Language file loaded successfully", "Translator"); } public static void LoadLangs() { @@ -152,14 +152,14 @@ public static class Translator } catch (KeyNotFoundException) { - Logger.Warn($"无效密钥:{tmp[0]}", "LoadCustomTranslation"); + Logger.Warn($"Invalid key:{tmp[0]}", "LoadCustomTranslation"); } } } } else { - Logger.Error($"找不到自定义翻译文件:{filename}", "LoadCustomTranslation"); + Logger.Error($"Custom translation file not found:{filename}", "LoadCustomTranslation"); } } diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 5a8b76a82..29dcf98b1 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -568,6 +568,7 @@ public static class Utils case CustomRoles.Aid: case CustomRoles.Escort: case CustomRoles.DonutDelivery: + case CustomRoles.Analyzer: case CustomRoles.Witness: case CustomRoles.Pursuer: case CustomRoles.Spiritcaller: diff --git a/Patches/DisconnectPatch.cs b/Patches/DisconnectPatch.cs index c2eedd1d6..e798e3c97 100644 --- a/Patches/DisconnectPatch.cs +++ b/Patches/DisconnectPatch.cs @@ -66,8 +66,70 @@ internal class ShowDisconnectPopupPatch if (StringReason.Contains("Reliable packet")) __instance.SetText(GetString("DCNotify.DCFromServer")); else if (StringReason.Contains("remote has not responded to")) __instance.SetText(GetString("DCNotify.DCFromServer")); break; + case DisconnectReasons.ExitGame: + break; + case DisconnectReasons.InvalidName: + break; + case DisconnectReasons.ConnectionLimit: + break; + case DisconnectReasons.Destroy: + break; + case DisconnectReasons.IncorrectGame: + break; + case DisconnectReasons.ServerRequest: + break; + case DisconnectReasons.ServerFull: + break; + case DisconnectReasons.InternalPlayerMissing: + break; + case DisconnectReasons.InternalNonceFailure: + break; + case DisconnectReasons.InternalConnectionToken: + break; + case DisconnectReasons.PlatformLock: + break; + case DisconnectReasons.MatchmakerInactivity: + break; + case DisconnectReasons.NoServersAvailable: + break; + case DisconnectReasons.QuickmatchDisabled: + break; + case DisconnectReasons.TooManyGames: + break; + case DisconnectReasons.QuickchatLock: + break; + case DisconnectReasons.MatchmakerFull: + break; + case DisconnectReasons.Sanctions: + break; + case DisconnectReasons.ServerError: + break; + case DisconnectReasons.SelfPlatformLock: + break; + case DisconnectReasons.TooManyRequests: + break; + case DisconnectReasons.IntentionalLeaving: + break; + case DisconnectReasons.FocusLostBackground: + break; + case DisconnectReasons.FocusLost: + break; + case DisconnectReasons.NewConnection: + break; + case DisconnectReasons.PlatformParentalControlsBlock: + break; + case DisconnectReasons.PlatformUserBlock: + break; + case DisconnectReasons.PlatformFailedToGetUserBlock: + break; + case DisconnectReasons.ServerNotFound: + break; + case DisconnectReasons.ClientTimeout: + break; + case DisconnectReasons.Unknown: + break; } } }, 0.01f, "Override Disconnect Text"); - } + } } \ No newline at end of file diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index a9322be30..c3f5de554 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -57,7 +57,7 @@ class HudManagerPatch Utils.CountAlivePlayers(); - bool shapeshifting = Main.CheckShapeshift.TryGetValue(player.PlayerId, out bool ss) && ss; + bool shapeshifting = player.shapeshifting; if (SetHudActivePatch.IsActive) { @@ -149,6 +149,9 @@ class HudManagerPatch //case CustomRoles.Counterfeiter: // __instance.KillButton.OverrideText(GetString("CounterfeiterButtonText")); // break; + case CustomRoles.Analyzer: + __instance.KillButton?.OverrideText(GetString("AnalyzerKillButtonText")); + break; case CustomRoles.Witness: __instance.KillButton?.OverrideText(GetString("WitnessButtonText")); break; @@ -671,7 +674,7 @@ class SetHudActivePatch } - if (Main.PlayerStates[player.PlayerId].SubRoles.Contains(CustomRoles.Oblivious)) + if (Main.PlayerStates.TryGetValue(player.PlayerId, out var ps) && ps.SubRoles.Contains(CustomRoles.Oblivious)) { __instance.ReportButton?.ToggleVisible(false); } diff --git a/Patches/HudSpritePatch.cs b/Patches/HudSpritePatch.cs index f5639be4b..7332861a1 100644 --- a/Patches/HudSpritePatch.cs +++ b/Patches/HudSpritePatch.cs @@ -34,7 +34,7 @@ public static class HudSpritePatch return; } - bool shapeshifting = Main.CheckShapeshift.TryGetValue(player.PlayerId, out bool ss) && ss; + bool shapeshifting = player.shapeshifting; if (!Kill) Kill = __instance.KillButton.graphic.sprite; if (!Ability) Ability = __instance.AbilityButton.graphic.sprite; @@ -231,6 +231,7 @@ public static class HudSpritePatch else newPetButton = CustomButton.Get("Mine"); break; + case CustomRoles.Analyzer: case CustomRoles.Witness: newKillButton = CustomButton.Get("Examine"); break; diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs index 40dd52d76..d9995d28e 100644 --- a/Patches/IntroPatch.cs +++ b/Patches/IntroPatch.cs @@ -447,7 +447,7 @@ class BeginImpostorPatch __instance.overlayHandle.color = Palette.ImpostorRed; return true; } - else if (role is CustomRoles.Sheriff or CustomRoles.Jailor or CustomRoles.SwordsMan or CustomRoles.Medic/* or CustomRoles.Counterfeiter*/ or CustomRoles.Witness or CustomRoles.Aid or CustomRoles.Escort or CustomRoles.DonutDelivery or CustomRoles.Monarch or CustomRoles.Farseer or CustomRoles.Admirer or CustomRoles.Deputy) + else if (role is CustomRoles.Sheriff or CustomRoles.Jailor or CustomRoles.SwordsMan or CustomRoles.Medic/* or CustomRoles.Counterfeiter*/ or CustomRoles.Witness or CustomRoles.Analyzer or CustomRoles.Aid or CustomRoles.Escort or CustomRoles.DonutDelivery or CustomRoles.Monarch or CustomRoles.Farseer or CustomRoles.Admirer or CustomRoles.Deputy) { yourTeam = new Il2CppSystem.Collections.Generic.List(); yourTeam.Add(PlayerControl.LocalPlayer); diff --git a/Patches/PlayerContorolPatch.cs b/Patches/PlayerContorolPatch.cs index b7eb799cc..d0708488f 100644 --- a/Patches/PlayerContorolPatch.cs +++ b/Patches/PlayerContorolPatch.cs @@ -217,6 +217,9 @@ class CheckMurderPatch case CustomRoles.Magician: Magician.OnCheckMurder(killer); break; + case CustomRoles.Analyzer: + Analyzer.OnCheckMurder(killer, target); + return false; case CustomRoles.DonutDelivery: DonutDelivery.OnCheckMurder(killer, target); return false; @@ -229,12 +232,6 @@ class CheckMurderPatch case CustomRoles.Cantankerous: if (Cantankerous.OnCheckMurder(killer)) return false; break; - case CustomRoles.Blackmailer: - if (!killer.CheckDoubleTrigger(target, () => - { - Blackmailer.ForBlackmailer.Add(target.PlayerId); - })) return false; - break; case CustomRoles.Postman: Postman.OnCheckMurder(killer, target); return false; @@ -324,7 +321,7 @@ class CheckMurderPatch break; case CustomRoles.Warlock: if (!Main.isCurseAndKill.ContainsKey(killer.PlayerId)) Main.isCurseAndKill[killer.PlayerId] = false; - if (!Main.CheckShapeshift[killer.PlayerId] && !Main.isCurseAndKill[killer.PlayerId]) + if (!killer.shapeshifting && !Main.isCurseAndKill[killer.PlayerId]) { //Warlockが変身時以外にキルしたら、呪われる処理 if (target.Is(CustomRoles.Needy) || target.Is(CustomRoles.Lazy)) return false; Main.isCursed = true; @@ -337,7 +334,7 @@ class CheckMurderPatch //RPC.RpcSyncCurseAndKill(); return false; } - if (Main.CheckShapeshift[killer.PlayerId]) + if (killer.shapeshifting) {//呪われてる人がいないくて変身してるときに通常キルになる killer.RpcCheckAndMurder(target); return false; @@ -1337,6 +1334,10 @@ class ShapeshiftPatch Sapper.OnShapeshift(shapeshifter); isSSneeded = false; break; + case CustomRoles.Blackmailer: + Blackmailer.ForBlackmailer.Add(target.PlayerId); + isSSneeded = false; + break; case CustomRoles.Warlock: if (Main.CursedPlayers[shapeshifter.PlayerId] != null)//呪われた人がいるか確認 { @@ -3238,6 +3239,9 @@ class EnterVentPatch case CustomRoles.Addict: Addict.OnEnterVent(pc, __instance); break; + case CustomRoles.CameraMan: + CameraMan.OnEnterVent(pc); + break; case CustomRoles.Alchemist: Alchemist.OnEnterVent(pc, __instance.Id); break; diff --git a/Patches/onGameStartedPatch.cs b/Patches/onGameStartedPatch.cs index 3442321ce..c9cfae121 100644 --- a/Patches/onGameStartedPatch.cs +++ b/Patches/onGameStartedPatch.cs @@ -231,6 +231,7 @@ internal class ChangeRoleSettings Benefactor.Init(); Aid.Init(); DonutDelivery.Init(); + Analyzer.Init(); Escort.Init(); Consort.Init(); Drainer.Init(); @@ -686,6 +687,9 @@ internal class SelectRolesPatch case CustomRoles.DonutDelivery: DonutDelivery.Add(pc.PlayerId); break; + case CustomRoles.Analyzer: + Analyzer.Add(pc.PlayerId); + break; case CustomRoles.Pursuer: Pursuer.Add(pc.PlayerId); break; diff --git a/Resources/String.csv b/Resources/String.csv index a238a9397..f062d6951 100644 --- a/Resources/String.csv +++ b/Resources/String.csv @@ -965,7 +965,6 @@ "DisableCalibrateDistributor","禁用校准分电器任务","Disable Calibrate Distributor Task","Отключить Задание ''Откалибровать Распределитель''","","" "DisableChartCourse","禁用标出航线任务","Disable Chart Course Task","Отключить Задание ''Проложить Маршрут''","","" "DisableStabilizeSteering","禁用稳定航向任务","Disable Stabilize Steering Task","Отключить Задание ''Выровнять Курс''","","" -"DisableCleanO2Filter","禁用清理树叶任务","Disable Clean O2 Filter Task","Отключить Задание ''Очистить Фильтр O2''","","" "DisableCleanO2Filter","禁用清理氧气过滤器任务","Disable Clean O2 Filter Task","Отключить Задание ''Очистить Фильтр O2''","","" "DisableUnlockManifolds","禁用解锁歧管任务","Disable Unlock Manifolds Task","Отключить Задание ''Открыть Коллекторы''","","" "DisablePrimeShields","禁用开启护盾任务","Disable Prime Shields Task","Отключить Задание ''Запустить Щиты''","","" @@ -1099,9 +1098,6 @@ "AllOpen","","Open All","","","" "RandomByDoor","","Random","","","" "KickAndroidPlayer","踢出使用安卓的玩家","Kick mobile players","Кикнуть игроков которые зашли в лобби через телефон","踢出使用Android平台遊玩的玩家","踢出使用安卓的玩家" -"KickXboxPlayer","踢出Xbox玩家","Kick Xbox players","","","" -"KickPlayStationPlayer","踢出PS玩家","Kick PlayStation players","","","" -"KickNintendoPlayer","踢出任天堂Switch玩家","Kick Nintendo Switch players","","","" "ShareLobby","允许车队姬自动群发您的房号","Allow TOHE-Chan Shares Lobby Code To Discord","Отправлять код вашей комнаты в Discord сервер TOHE (Больше не рабоатет)","允許車隊姬自動發送您的房號至Discord","Allow TOHE-chan share your lobby code to Discord" "ShareLobbyMinPlayer","房间人数达到多少时群发","Share Lobby Code When The Number Of Players Reaches","Минимально игроков для отправки кода","房間人數達到多少時發送","" "DisableVanillaRoles","禁用原版职业","Disable Vanilla Roles","Отключить ванильные Роли","禁用原版職業","禁用原版职业" @@ -1136,7 +1132,6 @@ "DisableSkeldCamera","禁用骷髅舰监控","Disable Cameras","Отключить Камеры","禁用The Skeld監控","禁用骷髅舰监控" "DisablePolusCamera","禁用波鲁斯监控设备","Disable Cameras","Отключить Камеры","禁用Polus監控","禁用波鲁斯监控设备" "DisableAirshipCamera","禁用飞艇监控","Disable Cameras","Отключить Камеры","禁用The Airship監控","禁用飞艇监控" -"DisableFungleCamera","","Disable Cameras","","","" "DisableMiraHQDoorLog","禁用米拉总部门禁记录","Disable DoorLog","Отключить Журналы","禁用Mira HQ通行紀錄","禁用米拉总部门禁记录" "DisablePolusVital","禁用波鲁斯生命监测装置","Disable Vitals","Отключить Пульсы","禁用Polus心電圖","禁用波鲁斯生命监测装置" "DisableAirshipVital","禁用飞艇生命监测装置","Disable Vitals","Отключить Пульсы","禁用The Airship心電圖","禁用飞艇生命监测装置" @@ -2500,7 +2495,7 @@ "DivinatorCheck.Result14","{0}是隐匿者、市长、被害妄想症、小偷或卫道士其中之一","{0} is either Anonymous, Mastermind, Spy, Mayor, Paranoid, Pickpocket, or Vindicator","","","" "DivinatorCheck.Result15","{0}是传染性的、病毒的、君主的、革命者的或魅魔的其中之一","{0} is either Infectious, Virus, Agitater, Monarch, Revolutionist, Express, or Cultist","","","" "DivinatorCheck.Result16","{0}是冤罪师、受虐狂、抑制者、修理工或破坏者其中之一","{0} is either Innocent, Sapper, Refugee, Bandit, Inhibitor, Mechanic, or Saboteur","","","" -"DivinatorCheck.Result17","{0}是医生、马里奥、小丑、潜伏者还是阳光开朗大男孩其中之一","{0} is either Medic, Vector, RiftMaker, Jester, The Glitch, Lurker, or Sunnyboy","","","" +"DivinatorCheck.Result17","{0}是医生、马里奥、小丑、潜伏者还是阳光开朗大男孩其中之一","{0} is either Medic, Vector, Analyzer, RiftMaker, Jester, The Glitch, Lurker, or Sunnyboy","","","" "DivinatorCheck.Result18","{0}是黑手党、惩罚者、教父、缺点者、幸运儿或失败者其中之一","{0} is either Nemesis, Hitman, Retributionist, Gangster, Glitch, Luckey, or Underdog","","","" "DivinatorCheck.Result19","{0}是邪恶赌怪、正义赌怪、潜藏者、梦魇、隐蔽者或变色龙其中之一","{0} is either Evil Guesser, Nice Guesser, Blackmailer, Eclipse, Reckless, Stalker, Camouflager, or Chameleon","","","" "DivinatorCheck.Result20","{0}是豺狼、跟班、独行者、投机者、追击者或自爆卡车其中之一","{0} is either Jackal, Sidekick, Duellist, WeaponMaster, Maverick, Opportunist, Pursuer, or Provocateur","","","" @@ -2553,7 +2548,7 @@ "pet_test","","Glitch Pet","","","" "pet_GuiltySpark","","Guilty Spark","","","" "pet_Stickmin","","H. Stickmin","","","" -"pet_HamPet","","Hammy","","","" +"## pet_HamPet","","Hammy","","","" "pet_Hamster","","Hampton","","","" "pet_Alien","","Headslug","","","" "pet_poro","","Heimerdinger's Poro","","","" @@ -2688,7 +2683,6 @@ "Consort","","Consort","","","" "ConsortInfo","","Role-Block and Kill Players","","","" "ConsortInfoLong","","(Impostors):\nAs the Consort, you can role-block a player which prevents them from killing, venting, sabotaging and reporting for some time by clicking your kill button on them once. Double click with your kill button on them to kill them normally.\n(The role-block duraiton is the same as the hack duration for The Glitch)","","","" -"Consort","","Consort","","","" "## Donut Delivery" "DonutDelivery","","Donut Delivery","","","" @@ -2817,7 +2811,6 @@ "PlagueDoctorInfectInactiveTime","","Infect Invalid Time","","","" "PlagueDoctorCanInfectSelf","","Can Infect Self","","","" "PlagueDoctorCanInfectVent","","Can Infect While In Vent","","","" -"PlagueDoctorInfectDistance","","Infect Distance","","","" "## Penguin" "Penguin","","Penguin","","","" diff --git a/Roles/Crewmate/Analyzer.cs b/Roles/Crewmate/Analyzer.cs new file mode 100644 index 000000000..0928cd86b --- /dev/null +++ b/Roles/Crewmate/Analyzer.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static TOHE.Options; +using static TOHE.Utils; +using static TOHE.Translator; +using Hazel; + +namespace TOHE.Roles.Crewmate +{ + internal class Analyzer + { + private static readonly int Id = 643100; + private static byte playerId = byte.MaxValue; + private static int UseLimit = 0; + + private static OptionItem UseLimitOpt; + private static OptionItem CD; + private static OptionItem Duration; + private static OptionItem SeeKillCount; + private static OptionItem SeeVentCount; + private static OptionItem SeeRoleBasis; + + public static Dictionary VentCount = []; + private static (byte, long) CurrentTarget = (byte.MaxValue, GetTimeStamp()); + + public static void SetupCustomOption() + { + SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Analyzer, 1); + UseLimitOpt = IntegerOptionItem.Create(Id + 10, "AbilityUseLimit", new(0, 5, 1), 3, TabGroup.CrewmateRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]) + .SetValueFormat(OptionFormat.Times); + CD = FloatOptionItem.Create(Id + 11, "AnalyzeCD", new(0f, 60f, 2.5f), 15f, TabGroup.CrewmateRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]) + .SetValueFormat(OptionFormat.Seconds); + Duration = IntegerOptionItem.Create(Id + 12, "AnalyzeDur", new(1, 30, 1), 5, TabGroup.CrewmateRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]) + .SetValueFormat(OptionFormat.Seconds); + SeeKillCount = BooleanOptionItem.Create(Id + 13, "AnalyzerSeeKillCount", true, TabGroup.CrewmateRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]); + SeeVentCount = BooleanOptionItem.Create(Id + 14, "AnalyzerSeeVentCount", true, TabGroup.CrewmateRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]); + SeeRoleBasis = BooleanOptionItem.Create(Id + 15, "AnalyzerSeeRoleBasis", true, TabGroup.CrewmateRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Analyzer]); + } + + public static bool CanUseKillButton => + + private static string GetRoleBasis(CustomRoles role) + { + var DYRole = role.GetDYRole(); + var VNRole = role.GetVNRole(); + if (DYRole == AmongUs.GameOptions.RoleTypes.Impostor) return ColorString(GetRoleColor(CustomRoles.Impostor), GetString("Impostor")); + else return VNRole switch + { + CustomRoles.Impostor => ColorString(GetRoleColor(CustomRoles.Impostor), GetString("Impostor")), + CustomRoles.Shapeshifter => ColorString(GetRoleColor(CustomRoles.Speedrunner), GetString("Shapeshifter")), + CustomRoles.Crewmate => ColorString(GetRoleColor(CustomRoles.Crewmate), GetString("Crewmate")), + CustomRoles.Engineer => ColorString(GetRoleColor(CustomRoles.Autocrat), GetString("Engineer")), + CustomRoles.Scientist => ColorString(GetRoleColor(CustomRoles.Doctor), GetString("Scientist")), + _ => string.Empty + }; + } + + private static int GetKillCount(byte id) => Main.PlayerStates.Count(x => x.Value.GetRealKiller() == id); + + private static int GetVentCount(byte id) => VentCount.TryGetValue(id, out var count) ? count : 0; + + public static void Init() + { + playerId = byte.MaxValue; + UseLimit = 0; + VentCount = []; + CurrentTarget = (byte.MaxValue, GetTimeStamp()); + } + + public static void Add(byte id) + { + playerId = id; + UseLimit = UseLimitOpt.GetInt(); + + if (!AmongUsClient.Instance.AmHost) return; + if (!Main.ResetCamPlayerList.Contains(id)) + Main.ResetCamPlayerList.Add(id); + } + + private static void SendRPCSyncTarget() + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncAnalyzerTarget, SendOption.Reliable, -1); + writer.Write(CurrentTarget.Item1); + writer.Write(CurrentTarget.Item2); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + + public static void ReceiveRPCSyncTarget(MessageReader reader) + { + var item1 = reader.ReadByte(); + var item2 = long.Parse(reader.ReadString()); + CurrentTarget = (item1, item2); + } + + public static void SendRPC() + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncAnalyzer, SendOption.Reliable, -1); + writer.Write(UseLimit); + writer.Write(VentCount.Count); + foreach (var item in VentCount) + { + writer.Write(item.Key); + writer.Write(item.Value); + } + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + + public static void ReceiveRPC(MessageReader reader) + { + UseLimit = reader.ReadInt32(); + + int length = reader.ReadInt32(); + for (int i = 0; i < length; i++) + { + var key = reader.ReadByte(); + var value = reader.ReadInt32(); + VentCount.Add(key, value); + } + } + } +} diff --git a/Roles/Crewmate/CopyCat.cs b/Roles/Crewmate/CopyCat.cs index 7b3d14753..38f304644 100644 --- a/Roles/Crewmate/CopyCat.cs +++ b/Roles/Crewmate/CopyCat.cs @@ -200,6 +200,7 @@ public static class CopyCat //bcoz im lazy CustomRoles.Escort or CustomRoles.DonutDelivery or + CustomRoles.Analyzer or //bcoz of arrows CustomRoles.Mortician or CustomRoles.Bloodhound or diff --git a/Roles/Crewmate/Divinator.cs b/Roles/Crewmate/Divinator.cs index 1902401e3..cc5fa8bb3 100644 --- a/Roles/Crewmate/Divinator.cs +++ b/Roles/Crewmate/Divinator.cs @@ -250,6 +250,7 @@ public static class Divinator CustomRoles.Mario or CustomRoles.Jester or CustomRoles.RiftMaker or + CustomRoles.Analyzer or CustomRoles.Lurker or CustomRoles.Glitch or CustomRoles.Sunnyboy diff --git a/Roles/Crewmate/Farseer.cs b/Roles/Crewmate/Farseer.cs index 47f010329..67ad1f682 100644 --- a/Roles/Crewmate/Farseer.cs +++ b/Roles/Crewmate/Farseer.cs @@ -43,6 +43,7 @@ namespace TOHE.Roles.Crewmate CustomRoles.NiceHacker, CustomRoles.Aid, CustomRoles.DonutDelivery, + CustomRoles.Analyzer, CustomRoles.Escort, CustomRoles.Tether, CustomRoles.Spy, diff --git a/Roles/Impostor/Assassin.cs b/Roles/Impostor/Assassin.cs index 4fec003f1..8a49aef17 100644 --- a/Roles/Impostor/Assassin.cs +++ b/Roles/Impostor/Assassin.cs @@ -55,7 +55,7 @@ internal static class Assassin MarkedPlayer.Add(playerId, targetId); } private static bool Shapeshifting(this PlayerControl pc) => pc.PlayerId.Shapeshifting(); - private static bool Shapeshifting(this byte id) => Main.CheckShapeshift.TryGetValue(id, out bool shapeshifting) && shapeshifting; + private static bool Shapeshifting(this byte id) => Utils.GetPlayerById(id).shapeshifting; public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = id.Shapeshifting() ? DefaultKillCooldown : MarkCooldown.GetFloat(); public static void ApplyGameOptions() => AURoleOptions.ShapeshifterCooldown = AssassinateCooldown.GetFloat(); public static bool CanUseKillButton(PlayerControl pc) diff --git a/Roles/Impostor/Blackmailer.cs b/Roles/Impostor/Blackmailer.cs index 66ec3b651..2a51e2232 100644 --- a/Roles/Impostor/Blackmailer.cs +++ b/Roles/Impostor/Blackmailer.cs @@ -15,8 +15,9 @@ public static class Blackmailer public static void SetupCustomOption() { SetupRoleOptions(Id, TabGroup.OtherRoles, CustomRoles.Blackmailer); - SkillCooldown = FloatOptionItem.Create(Id + 5, "BlackmailerSkillCooldown", new(2.5f, 60f, 2.5f), 30f, TabGroup.OtherRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Blackmailer]) - .SetValueFormat(OptionFormat.Seconds); + SkillCooldown = FloatOptionItem.Create(Id + 5, "BlackmailerSkillCooldown", new(2.5f, 60f, 2.5f), 30f, TabGroup.OtherRoles, false) + .SetParent(CustomRoleSpawnChances[CustomRoles.Blackmailer]) + .SetValueFormat(OptionFormat.Seconds); } public static void Init() { diff --git a/Roles/Impostor/Cantankerous.cs b/Roles/Impostor/Cantankerous.cs index 2a6b80858..3c84d57fa 100644 --- a/Roles/Impostor/Cantankerous.cs +++ b/Roles/Impostor/Cantankerous.cs @@ -45,7 +45,7 @@ namespace TOHE.Roles.Impostor private static void SendRPC(byte playerId, bool isPlus) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDruidLimit, SendOption.Reliable, -1); + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncCantankerousLimit, SendOption.Reliable, -1); writer.Write(playerId); writer.Write(isPlus); AmongUsClient.Instance.FinishRpcImmediately(writer); diff --git a/Roles/Impostor/Duellist.cs b/Roles/Impostor/Duellist.cs index 09ebf21e2..21da2bd6c 100644 --- a/Roles/Impostor/Duellist.cs +++ b/Roles/Impostor/Duellist.cs @@ -46,7 +46,7 @@ namespace TOHE.Roles.Impostor private static void SendRPC(byte duellistId, byte targetId) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDruidLimit, SendOption.Reliable, -1); + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncDuellistTarget, SendOption.Reliable, -1); writer.Write(duellistId); writer.Write(targetId); AmongUsClient.Instance.FinishRpcImmediately(writer); diff --git a/Roles/Impostor/Hangman.cs b/Roles/Impostor/Hangman.cs index 43db4824c..75bb5f90c 100644 --- a/Roles/Impostor/Hangman.cs +++ b/Roles/Impostor/Hangman.cs @@ -59,10 +59,10 @@ public static class Hangman if (HangLimit[killer.PlayerId] < 1) { - if (Main.CheckShapeshift.TryGetValue(killer.PlayerId, out var ss) && ss) return false; + if (killer.shapeshifting) return false; }; - if (Main.CheckShapeshift.TryGetValue(killer.PlayerId, out var s) && s) + if (killer.shapeshifting) { if (target.Is(CustomRoles.Pestilence)) return false; if (target.Is(CustomRoles.Veteran) && Main.VeteranInProtect.ContainsKey(target.PlayerId)) return false; diff --git a/Roles/Impostor/Morphling.cs b/Roles/Impostor/Morphling.cs index bbde0cf10..5e80eba9d 100644 --- a/Roles/Impostor/Morphling.cs +++ b/Roles/Impostor/Morphling.cs @@ -37,7 +37,7 @@ public static class Morphling } public static bool CanUseKillButton(byte playerId) => !Main.PlayerStates[playerId].IsDead - && Main.CheckShapeshift[playerId]; + && Utils.GetPlayerById(playerId).shapeshifting; public static void ApplyGameOptions() { diff --git a/Roles/Impostor/Nullifier.cs b/Roles/Impostor/Nullifier.cs index 07c77d9dc..3ea192b5a 100644 --- a/Roles/Impostor/Nullifier.cs +++ b/Roles/Impostor/Nullifier.cs @@ -71,6 +71,10 @@ namespace TOHE.Roles.Impostor DonutDelivery.DeliverLimit--; DonutDelivery.SendRPC(); break; + case CustomRoles.Analyzer: + Analyzer.UseLimit--; + Analyzer.SendRPC(); + break; case CustomRoles.Bloodhound: Bloodhound.UseLimit[target.PlayerId]--; Bloodhound.SendRPCPlus(target.PlayerId); diff --git a/Roles/Impostor/Undertaker.cs b/Roles/Impostor/Undertaker.cs index 0179b1a88..95b073138 100644 --- a/Roles/Impostor/Undertaker.cs +++ b/Roles/Impostor/Undertaker.cs @@ -55,7 +55,7 @@ internal static class Undertaker MarkedPlayer.Add(playerId, targetId); } private static bool Shapeshifting(this PlayerControl pc) => pc.PlayerId.Shapeshifting(); - private static bool Shapeshifting(this byte id) => Main.CheckShapeshift.TryGetValue(id, out bool shapeshifting) && shapeshifting; + private static bool Shapeshifting(this byte id) => Utils.GetPlayerById(id).shapeshifting; public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = id.Shapeshifting() ? DefaultKillCooldown : MarkCooldown.GetFloat(); public static void ApplyGameOptions() { diff --git a/Roles/Impostor/YinYanger.cs b/Roles/Impostor/YinYanger.cs index 7fef694bc..07373bb3d 100644 --- a/Roles/Impostor/YinYanger.cs +++ b/Roles/Impostor/YinYanger.cs @@ -52,7 +52,7 @@ namespace TOHE.Roles.Impostor public static void SendRPC(bool isClear, byte playerId = byte.MaxValue) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDruidLimit, SendOption.Reliable, -1); + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncYinYanger, SendOption.Reliable, -1); writer.Write(isClear); if (!isClear) writer.Write(playerId); AmongUsClient.Instance.FinishRpcImmediately(writer); diff --git a/Roles/Neutral/Doppelganger.cs b/Roles/Neutral/Doppelganger.cs index ef764acdc..72eefe176 100644 --- a/Roles/Neutral/Doppelganger.cs +++ b/Roles/Neutral/Doppelganger.cs @@ -130,7 +130,7 @@ public static class Doppelganger { if (killer == null || target == null || !IsEnable || Camouflage.IsCamouflage || Camouflager.IsActive) return; - if (Main.CheckShapeshift.TryGetValue(target.PlayerId, out bool isShapeshifitng) && isShapeshifitng) + if (target.shapeshifting) { Logger.Info("Target was shapeshifting", "Doppelganger"); return; diff --git a/main.cs b/main.cs index 63cc9d98a..a35ae148c 100644 --- a/main.cs +++ b/main.cs @@ -370,6 +370,7 @@ public class Main : BasePlugin {CustomRoles.NiceHacker, "#75fa4c"}, {CustomRoles.Aid, "#D7BDE2"}, {CustomRoles.DonutDelivery, "#a46efa"}, + {CustomRoles.Analyzer, "#33ddff"}, {CustomRoles.Escort, "#ff94e6"}, {CustomRoles.Spy, "#34495E"}, {CustomRoles.Doormaster, "#7FB3D5"}, @@ -738,6 +739,7 @@ public enum CustomRoles GuessManager, Escort, DonutDelivery, + Analyzer, Mayor, Jailor, Paranoia,