From 28f21cbf351e94a512cf9aa219622549e51b7671 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Tue, 31 Oct 2023 20:30:07 +0100 Subject: [PATCH] Fix a LOT of bugs & Add RPCs --- GameMode/FFAManager.cs | 24 +- Modules/CustomRoleSelector.cs | 10 +- Modules/CustomRolesHelper.cs | 2 +- Modules/DebugModeManager.cs | 7 +- Modules/DoubleTrigger.cs | 11 +- Modules/ExtendedPlayerControl.cs | 2 +- .../GameOptionsSender/GameOptionsSender.cs | 17 +- .../NormalGameOptionsSender.cs | 2 +- Modules/GameState.cs | 12 + Modules/LateTask.cs | 15 +- Modules/MeetingTimeManager.cs | 4 +- Modules/OptionHolder.cs | 9 +- Modules/OptionSaver.cs | 18 + Modules/RPC.cs | 116 ++++- Modules/Utils.cs | 40 +- Patches/ChatCommandPatch.cs | 111 ++--- Patches/CheckGameEndPatch.cs | 3 +- Patches/ControlPatch.cs | 2 +- Patches/ExilePatch.cs | 2 +- Patches/HudPatch.cs | 3 +- Patches/IntroPatch.cs | 1 - Patches/MainMenuManagerPatch.cs | 2 +- Patches/MeetingHudPatch.cs | 108 ++++- Patches/PetActionsPatch.cs | 50 +- Patches/PlayerContorolPatch.cs | 437 ++++++++++-------- Patches/PlayerJoinAndLeftPatch.cs | 4 +- Patches/RandomSpawnPatch.cs | 44 +- Patches/ShipStatusPatch.cs | 2 +- Patches/TaskAssignPatch.cs | 2 +- Patches/onGameStartedPatch.cs | 8 +- Resources/Config/EACList.txt | 8 +- Resources/String.csv | 11 +- Roles/Crewmate/Aid.cs | 2 +- Roles/Crewmate/Alchemist.cs | 24 + Roles/Crewmate/Bloodhound.cs | 20 + Roles/Crewmate/CameraMan.cs | 19 + Roles/Crewmate/Chameleon.cs | 18 + Roles/Crewmate/Divinator.cs | 19 + Roles/Crewmate/Doormaster.cs | 19 + Roles/Crewmate/Enigma.cs | 21 +- Roles/Crewmate/Judge.cs | 8 +- Roles/Crewmate/Mediumshiper.cs | 23 +- Roles/Crewmate/NiceHacker.cs | 19 + Roles/Crewmate/Oracle.cs | 19 + Roles/Crewmate/ParityCop.cs | 10 +- Roles/Crewmate/Ricochet.cs | 33 ++ Roles/Crewmate/SabotageMaster.cs | 20 +- Roles/Crewmate/Spy.cs | 48 ++ Roles/Crewmate/Tether.cs | 33 ++ Roles/Crewmate/Tracker.cs | 1 - Roles/Impostor/Disperser.cs | 6 +- Roles/Impostor/Hitman.cs | 19 +- Roles/Impostor/Mastermind.cs | 6 +- Roles/Neutral/Eclipse.cs | 20 +- Roles/Neutral/Glitch.cs | 109 ++++- Roles/Neutral/Magician.cs | 4 +- Roles/Neutral/Postman.cs | 6 +- Roles/Neutral/Pyromaniac.cs | 2 +- Roles/Neutral/Romantic.cs | 5 +- Roles/Neutral/Vengeance.cs | 52 ++- Roles/Neutral/WeaponMaster.cs | 18 + TOHE.csproj | 2 + main.cs | 4 +- 63 files changed, 1254 insertions(+), 442 deletions(-) diff --git a/GameMode/FFAManager.cs b/GameMode/FFAManager.cs index 36c2ce06c..a1145dd73 100644 --- a/GameMode/FFAManager.cs +++ b/GameMode/FFAManager.cs @@ -203,6 +203,8 @@ internal static class FFAManager if (FFA_EnableRandomAbilities.GetBool()) { + bool sync = false; + bool mark = false; byte EffectType; if (Main.NormalOptions.MapId != 4) EffectType = (byte)HashRandom.Next(0, 10); else EffectType = (byte)HashRandom.Next(4, 10); @@ -231,13 +233,16 @@ internal static class FFAManager } killer.Notify(GetString("FFA-Event-GetIncreasedSpeed"), FFA_ModifiedSpeedDuration.GetFloat()); Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat(); + sync = true; break; case 2: Main.AllPlayerKillCooldown[killer.PlayerId] = System.Math.Clamp(FFA_KCD.GetFloat() - 3f, 1f, 60f); killer.Notify(GetString("FFA-Event-GetLowKCD")); + sync = true; break; default: Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat(); + sync = true; break; } } @@ -261,32 +266,41 @@ internal static class FFAManager } killer.Notify(GetString("FFA-Event-GetDecreasedSpeed"), FFA_ModifiedSpeedDuration.GetFloat()); Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat(); + sync = true; break; case 1: Main.AllPlayerKillCooldown[killer.PlayerId] = System.Math.Clamp(FFA_KCD.GetFloat() + 3f, 1f, 60f); killer.Notify(GetString("FFA-Event-GetHighKCD")); + sync = true; break; case 2: FFALowerVisionList.TryAdd(killer.PlayerId, Utils.GetTimeStamp()); Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat(); killer.Notify(GetString("FFA-Event-GetLowVision")); + mark = true; break; default: Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat(); + sync = true; break; } } else // Mixed { - var rd = IRandom.Instance; - var vents = Object.FindObjectsOfType(); - var vent = vents[rd.Next(0, vents.Count)]; - _ = new LateTask(() => { Utils.TP(killer.NetTransform, new Vector2(vent.transform.position.x, vent.transform.position.y)); }, 0.5f, "FFA-Event-TP"); + _ = new LateTask(killer.TPtoRndVent, 0.5f, "FFA-Event-TP"); killer.Notify(GetString("FFA-Event-GetTP")); Main.AllPlayerKillCooldown[killer.PlayerId] = FFA_KCD.GetFloat(); } - killer.SyncSettings(); + if (sync) + { + mark = false; + killer.SyncSettings(); + } + if (mark) + { + killer.MarkDirtySettings(); + } } killer.Kill(target); diff --git a/Modules/CustomRoleSelector.cs b/Modules/CustomRoleSelector.cs index 7d6dd823d..cabc32dce 100644 --- a/Modules/CustomRoleSelector.cs +++ b/Modules/CustomRoleSelector.cs @@ -125,7 +125,7 @@ internal class CustomRoleSelector ImpOnList.Remove(select); rolesToAssign.Add(select); readyRoleNum++; - Logger.Info(select.ToString() + " 加入内鬼职业待选列表(优先)", "CustomRoleSelector"); + Logger.Info(select.ToString() + " Join the mole role waiting list (priority)", "CustomRoleSelector"); if (readyRoleNum >= playerCount) goto EndOfAssign; if (readyRoleNum >= optImpNum) break; } @@ -138,7 +138,7 @@ internal class CustomRoleSelector ImpRateList.Remove(select); rolesToAssign.Add(select); readyRoleNum++; - Logger.Info(select.ToString() + " 加入内鬼职业待选列表", "CustomRoleSelector"); + Logger.Info(select.ToString() + " Add to the role waiting list", "CustomRoleSelector"); if (readyRoleNum >= playerCount) goto EndOfAssign; if (readyRoleNum >= optImpNum) break; } @@ -351,7 +351,7 @@ internal class CustomRoleSelector var roleId = rd.Next(0, rolesToAssign.Count); RoleResult.Add(AllPlayer[0], rolesToAssign[roleId]); - Logger.Info($"职业分配:{AllPlayer[0].GetRealName()} => {rolesToAssign[roleId]}", "CustomRoleSelector"); + Logger.Info($"Role assigned:{AllPlayer[0].GetRealName()} => {rolesToAssign[roleId]}", "CustomRoleSelector"); AllPlayer.RemoveAt(0); rolesToAssign.RemoveAt(roleId); @@ -364,9 +364,9 @@ internal class CustomRoleSelector } if (AllPlayer.Any()) - Logger.Error("职业分配错误:存在未被分配职业的玩家", "CustomRoleSelector"); + Logger.Error("Role assignment error: There are players who have not been assigned a role", "CustomRoleSelector"); if (rolesToAssign.Any()) - Logger.Error("职业分配错误:存在未被分配的职业", "CustomRoleSelector"); + Logger.Error("Team assignment error: There is an unassigned team", "CustomRoleSelector"); } diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index 09fad47c3..2a8a04d6b 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -87,7 +87,7 @@ internal static class CustomRolesHelper CustomRoles.Spy => CustomRoles.Crewmate, CustomRoles.Ricochet => CustomRoles.Crewmate, CustomRoles.Tether => Options.UsePets.GetBool() ? CustomRoles.Crewmate : CustomRoles.Engineer, - CustomRoles.Doormaster => CustomRoles.Engineer, + CustomRoles.Doormaster => Options.UsePets.GetBool() ? CustomRoles.Crewmate : CustomRoles.Engineer, CustomRoles.Aid => CustomRoles.Impostor, CustomRoles.Escapee => Options.UsePets.GetBool() ? CustomRoles.Impostor : CustomRoles.Shapeshifter, CustomRoles.NiceGuesser => CustomRoles.Crewmate, diff --git a/Modules/DebugModeManager.cs b/Modules/DebugModeManager.cs index 1bb0904be..0b4e9020a 100644 --- a/Modules/DebugModeManager.cs +++ b/Modules/DebugModeManager.cs @@ -6,12 +6,7 @@ public static class DebugModeManager { // これが有効の時、通常のゲームに支障のないデバッグ機能(詳細ログ・ゲーム外でのデバッグ表示など)が有効化される。 // また、ゲーム内オプションでデバッグモードを有効化することができる。 - public static bool AmDebugger { get; private set; } = -#if DEBUG -true; -#else -false; -#endif + public static bool AmDebugger { get; private set; } // これが有効の時、通常のゲームを破壊する可能性のある強力なデバッグ機能(テレポートなど)が有効化される。 public static bool IsDebugMode => AmDebugger && EnableDebugMode != null && EnableDebugMode.GetBool(); diff --git a/Modules/DoubleTrigger.cs b/Modules/DoubleTrigger.cs index c2c9d79a6..d090657f3 100644 --- a/Modules/DoubleTrigger.cs +++ b/Modules/DoubleTrigger.cs @@ -27,7 +27,14 @@ static class DoubleTrigger return PlayerIdList.Contains(killer.PlayerId); } - /// 一回目アクション時 false、2回目アクション時true + /// + /// Checks for whether the killer pressed their kill button twice on the same player + /// + /// Who the killer is + /// Who the killer is targeting with the kill button + /// The action that should be done if the killer only presses their kill button once + /// Whether the Action should be done or not + /// Returns true if the kill button is clicked twice within 1 second. Otherwise, does the Action specified in the parameter firstAction and returns false public static bool CheckDoubleTrigger(this PlayerControl killer, PlayerControl target, Action firstAction, bool doAction = true) { if (FirstTriggerTimer.ContainsKey(killer.PlayerId)) @@ -67,7 +74,7 @@ static class DoubleTrigger if (FirstTriggerTimer[playerId] <= 0) { Logger.Info($"{player.name} DoSingleAction", "DoubleTrigger"); - FirstTriggerAction[playerId](); + if (FirstTriggerAction.ContainsKey(playerId)) FirstTriggerAction[playerId](); FirstTriggerTimer.Remove(playerId); FirstTriggerTarget.Remove(playerId); diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index 4c08ae8e0..51ced20d9 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -385,7 +385,7 @@ static class ExtendedPlayerControl } public static string GetNameWithRole(this PlayerControl player, bool forUser = false) { - return $"{player?.Data?.PlayerName}" + (GameStates.IsInGame && Options.CurrentGameMode != CustomGameMode.FFA ? $"({player?.GetAllRoleName(forUser).RemoveHtmlTags()})" : string.Empty); + return $"{player?.Data?.PlayerName}" + (GameStates.IsInGame && Options.CurrentGameMode != CustomGameMode.FFA ? $" ({player?.GetAllRoleName(forUser).RemoveHtmlTags().Replace('\n', ' ')})" : string.Empty); } public static string GetRoleColorCode(this PlayerControl player) { diff --git a/Modules/GameOptionsSender/GameOptionsSender.cs b/Modules/GameOptionsSender/GameOptionsSender.cs index 5743bf35c..959409b57 100644 --- a/Modules/GameOptionsSender/GameOptionsSender.cs +++ b/Modules/GameOptionsSender/GameOptionsSender.cs @@ -61,13 +61,20 @@ public abstract class GameOptionsSender } public virtual void SendOptionsArray(Il2CppStructArray optionArray) { - for (byte i = 0; i < GameManager.Instance.LogicComponents.Count; i++) + try { - if (GameManager.Instance.LogicComponents[(Index)i].TryCast(out _)) + for (byte i = 0; i < GameManager.Instance?.LogicComponents?.Count; i++) { - SendOptionsArray(optionArray, i, -1); + if (GameManager.Instance.LogicComponents[(Index)i].TryCast(out _)) + { + SendOptionsArray(optionArray, i, -1); + } } } + catch (Exception ex) + { + Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray-1"); + } } protected virtual void SendOptionsArray(Il2CppStructArray optionArray, byte LogicOptionsIndex, int targetClientId) { @@ -95,9 +102,9 @@ public abstract class GameOptionsSender AmongUsClient.Instance.SendOrDisconnect(writer); writer.Recycle(); } - catch (System.Exception ex) + catch (Exception ex) { - Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray"); + Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray-2"); } } public abstract IGameOptions BuildGameOptions(); diff --git a/Modules/GameOptionsSender/NormalGameOptionsSender.cs b/Modules/GameOptionsSender/NormalGameOptionsSender.cs index 7be460b7a..5ed4cfb7d 100644 --- a/Modules/GameOptionsSender/NormalGameOptionsSender.cs +++ b/Modules/GameOptionsSender/NormalGameOptionsSender.cs @@ -24,7 +24,7 @@ public class NormalGameOptionsSender : GameOptionsSender catch (Exception ex) { Logger.Fatal(ex.ToString(), "NormalGameOptionsSender.IsDirty.Get"); - return true; + return _logicOptions != null && _logicOptions.IsDirty; } } protected set diff --git a/Modules/GameState.cs b/Modules/GameState.cs index ece75c923..676b1bd3c 100644 --- a/Modules/GameState.cs +++ b/Modules/GameState.cs @@ -413,6 +413,7 @@ public class TaskState { case CustomRoles.Divinator: Divinator.CheckLimit[player.PlayerId] += Divinator.AbilityUseGainWithEachTaskCompleted.GetFloat(); + Divinator.SendRPC(player.PlayerId, false); break; case CustomRoles.Veteran: Main.VeteranNumOfUsed[player.PlayerId] += Options.VeteranAbilityUseGainWithEachTaskCompleted.GetFloat(); @@ -437,46 +438,57 @@ public class TaskState break; case CustomRoles.Mediumshiper: Mediumshiper.ContactLimit[player.PlayerId] += Mediumshiper.MediumAbilityUseGainWithEachTaskCompleted.GetFloat(); + Mediumshiper.SendRPC(player.PlayerId, false); break; case CustomRoles.ParityCop: ParityCop.MaxCheckLimit[player.PlayerId] += ParityCop.ParityAbilityUseGainWithEachTaskCompleted.GetFloat(); break; case CustomRoles.Oracle: Oracle.CheckLimit[player.PlayerId] += Oracle.OracleAbilityUseGainWithEachTaskCompleted.GetFloat(); + Oracle.SendRPC(player.PlayerId, false); break; case CustomRoles.SabotageMaster: SabotageMaster.UsedSkillCount -= SabotageMaster.SMAbilityUseGainWithEachTaskCompleted.GetFloat(); + SabotageMaster.SendRPC(SabotageMaster.UsedSkillCount); break; case CustomRoles.Tracker: Tracker.TrackLimit[player.PlayerId] += Tracker.TrackerAbilityUseGainWithEachTaskCompleted.GetFloat(); break; case CustomRoles.Bloodhound: Bloodhound.UseLimit[player.PlayerId] += Bloodhound.BloodhoundAbilityUseGainWithEachTaskCompleted.GetFloat(); + Bloodhound.SendRPCPlus(player.PlayerId, false); break; case CustomRoles.Chameleon: Chameleon.UseLimit[player.PlayerId] += Chameleon.ChameleonAbilityUseGainWithEachTaskCompleted.GetFloat(); + Chameleon.SendRPCPlus(player.PlayerId, false); break; case CustomRoles.NiceSwapper: NiceSwapper.NiceSwappermax[player.PlayerId] += NiceSwapper.NiceSwapperAbilityUseGainWithEachTaskCompleted.GetFloat(); break; case CustomRoles.Doormaster: Doormaster.UseLimit[player.PlayerId] += Doormaster.DoormasterAbilityUseGainWithEachTaskCompleted.GetFloat(); + Doormaster.SendRPC(player.PlayerId, false); break; case CustomRoles.Ricochet: Ricochet.UseLimit[player.PlayerId] += Ricochet.RicochetAbilityUseGainWithEachTaskCompleted.GetFloat(); + Ricochet.SendRPC(player.PlayerId, false); break; case CustomRoles.Tether: Tether.UseLimit[player.PlayerId] += Tether.TetherAbilityUseGainWithEachTaskCompleted.GetFloat(); + Tether.SendRPC(player.PlayerId, false); break; case CustomRoles.Spy: Spy.UseLimit[player.PlayerId] += Spy.SpyAbilityUseGainWithEachTaskCompleted.GetFloat(); + Spy.SendAbilityRPC(player.PlayerId); break; case CustomRoles.NiceHacker: if (!player.IsModClient()) NiceHacker.UseLimit[player.PlayerId] += NiceHacker.NiceHackerAbilityUseGainWithEachTaskCompleted.GetFloat(); else NiceHacker.UseLimitSeconds[player.PlayerId] += NiceHacker.NiceHackerAbilityUseGainWithEachTaskCompleted.GetInt() * NiceHacker.ModdedClientAbilityUseSecondsMultiplier.GetInt(); + NiceHacker.SendRPC(player.PlayerId, NiceHacker.UseLimitSeconds[player.PlayerId]); break; case CustomRoles.CameraMan: CameraMan.UseLimit[player.PlayerId] += CameraMan.CameraManAbilityUseGainWithEachTaskCompleted.GetFloat(); + CameraMan.SendRPC(player.PlayerId, false); break; } } diff --git a/Modules/LateTask.cs b/Modules/LateTask.cs index 0f50d7491..736e19fc9 100644 --- a/Modules/LateTask.cs +++ b/Modules/LateTask.cs @@ -8,6 +8,7 @@ class LateTask public string name; public float timer; public Action action; + public bool log; public static List Tasks = new(); public bool Run(float deltaTime) { @@ -19,13 +20,21 @@ class LateTask } return false; } - public LateTask(Action action, float time, string name = "No Name Task") + /// + /// Creates a task that will be automatically completed after the specified amount of time + /// + /// The delayed task + /// The time to wait until the task is run + /// The name of the task + /// Whether to send log of the creation of the Late Task + public LateTask(Action action, float time, string name = "No Name Task", bool log = true) { this.action = action; timer = time; this.name = name; + this.log = log; Tasks.Add(this); - if (name != "") + if (name != "" && log) Logger.Info("\"" + name + "\" is created", "LateTask"); } public static void Update(float deltaTime) @@ -38,7 +47,7 @@ class LateTask { if (task.Run(deltaTime)) { - if (task.name != string.Empty) + if (task.name != string.Empty && task.log) Logger.Info($"\"{task.name}\" is finished", "LateTask"); TasksToRemove.Add(task); } diff --git a/Modules/MeetingTimeManager.cs b/Modules/MeetingTimeManager.cs index eff4c387c..874c62184 100644 --- a/Modules/MeetingTimeManager.cs +++ b/Modules/MeetingTimeManager.cs @@ -35,7 +35,7 @@ public class MeetingTimeManager { DiscussionTime = 0; VotingTime = Options.AllAliveMeetingTime.GetInt(); - Logger.Info($"DiscussionTime:{DiscussionTime}, VotingTime{VotingTime}", "MeetingTimeManager.OnReportDeadBody"); + Logger.Info($"Discussion Time: {DiscussionTime}s, Voting Time: {VotingTime}s", "MeetingTimeManager.OnReportDeadBody"); return; } @@ -74,6 +74,6 @@ public class MeetingTimeManager DiscussionTime = 0; } } - Logger.Info($"DiscussionTime:{DiscussionTime}, VotingTime{VotingTime}", "MeetingTimeManager.OnReportDeadBody"); + Logger.Info($"Discussion Time: {DiscussionTime}s, Voting Time: {VotingTime}s", "MeetingTimeManager.OnReportDeadBody"); } } \ No newline at end of file diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index a75d99e0d..30dbca8c5 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -756,6 +756,7 @@ public static class Options public static OptionItem EndWhenPlayerBug; public static OptionItem UsePets; + public static OptionItem UseVoteCancelling; public static OptionItem EnableUpMode; public static OptionItem AutoKickStart; public static OptionItem AutoKickStartAsBan; @@ -913,7 +914,8 @@ public static class Options OptionSaver.Initialize(); // 预设 - _ = PresetOptionItem.Create(0, TabGroup.SystemSettings) + int defaultPresetNumber = OptionSaver.GetDefaultPresetNumber(); + _ = PresetOptionItem.Create(defaultPresetNumber, TabGroup.SystemSettings) .SetColor(new Color32(255, 235, 4, byte.MaxValue)) .SetHeader(true); @@ -2835,6 +2837,11 @@ public static class Options .SetHeader(true) .SetColor(new Color32(60, 0, 255, byte.MaxValue)); + UseVoteCancelling = BooleanOptionItem.Create(23852, "UseVoteCancelling", false, TabGroup.TaskSettings, false) + .SetGameMode(CustomGameMode.Standard) + .SetHeader(true) + .SetColor(new Color32(0, 65, 196, byte.MaxValue)); + //Disable Short Tasks DisableShortTasks = BooleanOptionItem.Create(23000, "DisableShortTasks", false, TabGroup.TaskSettings, false) diff --git a/Modules/OptionSaver.cs b/Modules/OptionSaver.cs index 29cc24c4f..2cb9555c8 100644 --- a/Modules/OptionSaver.cs +++ b/Modules/OptionSaver.cs @@ -10,6 +10,18 @@ public static class OptionSaver private static readonly DirectoryInfo SaveDataDirectoryInfo = new("./TOHE-DATA/SaveData/"); private static readonly FileInfo OptionSaverFileInfo = new($"{SaveDataDirectoryInfo.FullName}/Options.json"); private static readonly LogHandler logger = Logger.Handler(nameof(OptionSaver)); + private static readonly FileInfo DefaultPresetFileInfo = new($"{SaveDataDirectoryInfo.FullName}/DefaultPreset.txt"); + private static int DefaultPresetNumber; + + public static int GetDefaultPresetNumber() + { + if (DefaultPresetFileInfo.Exists) + { + string presetNmber = File.ReadAllText(DefaultPresetFileInfo.FullName); + if (int.TryParse(presetNmber, out int number) && number >= 0 && number <= 4) return number; + } + return 0; + } public static void Initialize() { @@ -22,6 +34,10 @@ public static class OptionSaver { OptionSaverFileInfo.Create().Dispose(); } + if (!DefaultPresetFileInfo.Exists) + { + DefaultPresetFileInfo.Create().Dispose(); + } } /// 現在のオプションからjsonシリアライズ用のオブジェクトを生成 private static SerializableOptionsData GenerateOptionsData() @@ -43,6 +59,7 @@ public static class OptionSaver Logger.Warn($"Duplicate preset option ID: {option.Id}", "Options Load"); } } + DefaultPresetNumber = singleOptions[0]; return new SerializableOptionsData { Version = Version, @@ -88,6 +105,7 @@ public static class OptionSaver var jsonString = JsonSerializer.Serialize(GenerateOptionsData(), new JsonSerializerOptions { WriteIndented = true, }); File.WriteAllText(OptionSaverFileInfo.FullName, jsonString); + File.WriteAllText(DefaultPresetFileInfo.FullName, DefaultPresetNumber.ToString()); } /// jsonファイルからオプションを読み込み public static void Load() diff --git a/Modules/RPC.cs b/Modules/RPC.cs index 18e3d8f9e..c55b3a9c8 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -58,6 +58,34 @@ enum CustomRPC //Roles SetDrawPlayer, + SetAlchemistPotion, + SetRicochetTarget, + SetTetherTarget, + SetHitmanTarget, + SetWeaponMasterMode, + SetEclipseVision, + SyncGlitchLongs, + SyncGlitchTimers, + SyncGlitchSS, + SyncGlitchMimic, + SyncGlitchKill, + SyncGlitchHack, + SyncVengeanceTimer, + SyncVengeanceData, + SpyRedNameSync, + SpyAbilitySync, + SpyRedNameRemove, + SetDivinatorLimit, + SetMediumshiperLimit, + SetOracleLimit, + SetSabotageMasterLimit, + SetDoormasterLimit, + SetRicochetLimit, + SetTetherLimit, + SetNiceHackerLimit, + SetCameraManLimit, + BloodhoundIncreaseAbilityUseByOne, + SetChameleonLimit, SetCurrentDrawTarget, SetCPTasksDone, SetGamerHealth, @@ -216,7 +244,7 @@ internal class RPCHandlerPatch case CustomRPC.AntiBlackout: if (Options.EndWhenPlayerBug.GetBool()) { - Logger.Fatal($"{__instance?.Data?.PlayerName}({__instance.PlayerId}): {reader.ReadString()} 错误,根据设定终止游戏", "Anti-black"); + Logger.Fatal($"{__instance?.Data?.PlayerName}({__instance.PlayerId}): {reader.ReadString()} - Error, terminate the game according to settings", "Anti-blackout"); ChatUpdatePatch.DoBlockChat = true; Main.OverrideWelcomeMsg = string.Format(GetString("RpcAntiBlackOutNotifyInLobby"), __instance?.Data?.PlayerName, GetString("EndWhenPlayerBug")); _ = new LateTask(() => @@ -232,7 +260,7 @@ internal class RPCHandlerPatch } else if (GameStates.IsOnlineGame) { - Logger.Fatal($"{__instance?.Data?.PlayerName}({__instance.PlayerId}): Change Role Setting Postfix 错误,根据设定继续游戏", "Anti-black"); + Logger.Fatal($"{__instance?.Data?.PlayerName}({__instance.PlayerId}): Change Role Setting Postfix - Error, continue the game according to settings", "Anti-blackout"); _ = new LateTask(() => { Logger.SendInGame(string.Format(GetString("RpcAntiBlackOutIgnored"), __instance?.Data?.PlayerName), true); @@ -387,6 +415,90 @@ internal class RPCHandlerPatch case CustomRPC.SniperSync: Sniper.ReceiveRPC(reader); break; + case CustomRPC.SpyRedNameSync: + Spy.ReceiveRPC(reader); + break; + case CustomRPC.SpyAbilitySync: + Spy.ReceiveRPC(reader, isAbility: true); + break; + case CustomRPC.SpyRedNameRemove: + Spy.ReceiveRPC(reader, isRemove: true); + break; + case CustomRPC.SetDivinatorLimit: + Divinator.ReceiveRPC(reader); + break; + case CustomRPC.SetAlchemistPotion: + Alchemist.ReceiveRPCData(reader); + break; + case CustomRPC.SetRicochetLimit: + Ricochet.ReceiveRPC(reader); + break; + case CustomRPC.SetRicochetTarget: + Ricochet.ReceiveRPCSyncTarget(reader); + break; + case CustomRPC.SetTetherTarget: + Tether.ReceiveRPCSyncTarget(reader); + break; + case CustomRPC.SetTetherLimit: + Tether.ReceiveRPC(reader); + break; + case CustomRPC.SetHitmanTarget: + Hitman.ReceiveRPC(reader); + break; + case CustomRPC.SetWeaponMasterMode: + WeaponMaster.ReceiveRPC(reader); + break; + case CustomRPC.SetEclipseVision: + Eclipse.ReceiveRPC(reader); + break; + case CustomRPC.SyncGlitchHack: + Glitch.ReceiveRPCSyncHack(reader); + break; + case CustomRPC.SyncGlitchKill: + Glitch.ReceiveRPCSyncKill(reader); + break; + case CustomRPC.SyncGlitchLongs: + Glitch.ReceiveRPCSyncLongs(reader); + break; + case CustomRPC.SyncGlitchMimic: + Glitch.ReceiveRPCSyncMimic(reader); + break; + case CustomRPC.SyncGlitchSS: + Glitch.ReceiveRPCSyncSS(reader); + break; + case CustomRPC.SyncGlitchTimers: + Glitch.ReceiveRPCSyncTimers(reader); + break; + case CustomRPC.SyncVengeanceData: + Vengeance.ReceiveRPC(reader); + break; + case CustomRPC.SyncVengeanceTimer: + Vengeance.ReceiveRPCSyncTimer(reader); + break; + case CustomRPC.SetMediumshiperLimit: + Mediumshiper.ReceiveRPC(reader); + break; + case CustomRPC.SetOracleLimit: + Oracle.ReceiveRPC(reader); + break; + case CustomRPC.SetSabotageMasterLimit: + SabotageMaster.ReceiveRPC(reader); + break; + case CustomRPC.SetDoormasterLimit: + Doormaster.ReceiveRPC(reader); + break; + case CustomRPC.SetNiceHackerLimit: + NiceHacker.ReceiveRPC(reader); + break; + case CustomRPC.SetCameraManLimit: + CameraMan.ReceiveRPC(reader); + break; + case CustomRPC.BloodhoundIncreaseAbilityUseByOne: + Bloodhound.ReceiveRPCPlus(reader); + break; + case CustomRPC.SetChameleonLimit: + Chameleon.ReceiveRPCPlus(reader); + break; case CustomRPC.SetLoversPlayers: Main.LoversPlayers.Clear(); int count = reader.ReadInt32(); diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 266e13e2d..1d99674aa 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -82,8 +82,6 @@ public static class Utils public static void TP(CustomNetworkTransform nt, Vector2 location) { - location += new Vector2(0, 0.3636f); - var pc = nt.myPlayer; if (pc.inVent || pc.inMovingPlat || !pc.IsAlive()) { @@ -91,18 +89,34 @@ public static class Utils return; } - if (AmongUsClient.Instance.AmHost) nt.SnapTo(location); + // Modded + nt.SnapTo(location, (ushort)(nt.lastSequenceId + 8)); - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(nt.NetId, (byte)RpcCalls.SnapTo, SendOption.None); - { - //nt.WriteVector2(location, writer); - NetHelpers.WriteVector2(location, writer); - writer.Write(nt.lastSequenceId); - } - AmongUsClient.Instance.FinishRpcImmediately(writer); + // Vanilla + MessageWriter messageWriter = AmongUsClient.Instance.StartRpcImmediately(nt.NetId, (byte)RpcCalls.SnapTo, SendOption.Reliable); + NetHelpers.WriteVector2(location, messageWriter); + messageWriter.Write(nt.lastSequenceId + 10U); + AmongUsClient.Instance.FinishRpcImmediately(messageWriter); Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} => {location}", "TP"); } + public static void TP(this PlayerControl pc, Vector2 location) + { + TP(pc.NetTransform, location); + } + public static void TPtoRndVent(this PlayerControl pc) + { + TPtoRndVent(pc.NetTransform); + } + public static void TPtoRndVent(CustomNetworkTransform nt) + { + var vents = UnityEngine.Object.FindObjectsOfType(); + var vent = vents[IRandom.Instance.Next(0, vents.Count)]; + + Logger.Info($"{nt.myPlayer.GetNameWithRole().RemoveHtmlTags()} => {vent.transform.position} (vent)", "TP"); + + TP(nt, new Vector2(vent.transform.position.x, vent.transform.position.y + 0.3636f)); + } public static ClientData GetClientById(int id) { try @@ -1207,6 +1221,12 @@ public static class Utils if (Options.NoGameEnd.GetBool()) { SendMessage(GetString("NoGameEndInfo"), PlayerId); } } + /// + /// Gets all players within a specified radius from the specified location + /// + /// The radius + /// The location which the radius is counted from + /// A list containing all PlayerControls within the specified range from the specified location public static List GetPlayersInRadius(float radius, Vector2 from) { var list = new List(); diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 09b5d8ba1..4b6773a11 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -76,6 +76,7 @@ internal class ChatCommands } if (AmongUsClient.Instance.AmHost) { + var localPlayerId = PlayerControl.LocalPlayer.PlayerId; Main.isChatCommand = true; switch (args[0]) { @@ -83,7 +84,7 @@ internal class ChatCommands case "/winner": canceled = true; if (!Main.winnerNameList.Any()) Utils.SendMessage(GetString("NoInfoExists")); - else Utils.SendMessage("Winner: " + string.Join(",", Main.winnerNameList)); + else Utils.SendMessage("Winners:\n" + string.Join(",", Main.winnerNameList)); break; case "/l": @@ -99,7 +100,7 @@ internal class ChatCommands canceled = true; if (args.Length < 1) break; if (args[1].Length is > 10 or < 1) - Utils.SendMessage(GetString("Message.AllowNameLength"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.AllowNameLength"), localPlayerId); else Main.nickName = args[1]; break; @@ -116,11 +117,11 @@ internal class ChatCommands case "/level": canceled = true; subArgs = args.Length < 2 ? string.Empty : args[1]; - Utils.SendMessage(string.Format(GetString("Message.SetLevel"), subArgs), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(string.Format(GetString("Message.SetLevel"), subArgs), localPlayerId); _ = int.TryParse(subArgs, out int input); if (input is < 1 or > 999) { - Utils.SendMessage(GetString("Message.AllowLevelRange"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.AllowLevelRange"), localPlayerId); break; } var number = Convert.ToUInt32(input); @@ -183,21 +184,21 @@ internal class ChatCommands if (!PlayerControl.LocalPlayer.FriendCode.GetDevUser().IsUp) break; if (!Options.EnableUpMode.GetBool()) { - Utils.SendMessage(string.Format(GetString("Message.YTPlanDisabled"), GetString("EnableYTPlan")), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(string.Format(GetString("Message.YTPlanDisabled"), GetString("EnableYTPlan")), localPlayerId); break; } if (!GameStates.IsLobby) { - Utils.SendMessage(GetString("Message.OnlyCanUseInLobby"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.OnlyCanUseInLobby"), localPlayerId); break; } - SendRolesInfo(subArgs, PlayerControl.LocalPlayer.PlayerId, isUp: true); + SendRolesInfo(subArgs, localPlayerId, isUp: true); break; case "/h": case "/help": canceled = true; - Utils.ShowHelp(PlayerControl.LocalPlayer.PlayerId); + Utils.ShowHelp(localPlayerId); break; case "/kcount": canceled = true; @@ -206,19 +207,19 @@ internal class ChatCommands int neutralnum = 0; for (int i = 0; i < Main.AllAlivePlayerControls.Count; i++) { - PlayerControl players = Main.AllAlivePlayerControls[i]; + PlayerControl pc = Main.AllAlivePlayerControls[i]; if (Options.ShowImpRemainOnEject.GetBool()) { - if (players.GetCustomRole().IsImpostor()) + if (pc.GetCustomRole().IsImpostor()) impnum++; } if (Options.ShowNKRemainOnEject.GetBool()) { - if (players.GetCustomRole().IsNK()) + if (pc.GetCustomRole().IsNK()) neutralnum++; } } - Utils.SendMessage($"There {(impnum == 1 ? "is" : "are")}\n{impnum} {(impnum == 1 ? "Impostor" : "Impostors")} and {neutralnum} {(neutralnum == 1 ? "Neutral Killer" : "Neutral Killers")} left.", PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage($"There {(impnum == 1 ? "is" : "are")}\n{impnum} {(impnum == 1 ? "Impostor" : "Impostors")} and {neutralnum} {(neutralnum == 1 ? "Neutral Killer" : "Neutral Killers")} left.", localPlayerId); break; case "/m": case "/myrole": @@ -241,7 +242,7 @@ internal class ChatCommands Utils.SendMessage(sb.ToString(), lp.PlayerId); } else - Utils.SendMessage((PlayerControl.LocalPlayer.FriendCode.GetDevUser().HasTag() ? "\n" : string.Empty) + GetString("Message.CanNotUseInLobby"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage((PlayerControl.LocalPlayer.FriendCode.GetDevUser().HasTag() ? "\n" : string.Empty) + GetString("Message.CanNotUseInLobby"), localPlayerId); break; case "/t": @@ -274,41 +275,41 @@ internal class ChatCommands // Check if the kick command is enabled in the settings if (Options.ApplyModeratorList.GetValue() == 0) { - Utils.SendMessage(GetString("KickCommandDisabled"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("KickCommandDisabled"), localPlayerId); break; } // Check if the player has the necessary privileges to use the command if (!IsPlayerModerator(PlayerControl.LocalPlayer.FriendCode)) { - Utils.SendMessage(GetString("KickCommandNoAccess"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("KickCommandNoAccess"), localPlayerId); break; } subArgs = args.Length < 2 ? string.Empty : args[1]; if (string.IsNullOrEmpty(subArgs) || !byte.TryParse(subArgs, out byte kickPlayerId)) { - Utils.SendMessage(GetString("KickCommandInvalidID"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("KickCommandInvalidID"), localPlayerId); break; } if (kickPlayerId == 0) { - Utils.SendMessage(GetString("KickCommandKickHost"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("KickCommandKickHost"), localPlayerId); break; } var kickedPlayer = Utils.GetPlayerById(kickPlayerId); if (kickedPlayer == null) { - Utils.SendMessage(GetString("KickCommandInvalidID"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("KickCommandInvalidID"), localPlayerId); break; } // Prevent moderators from kicking other moderators if (IsPlayerModerator(kickedPlayer.FriendCode)) { - Utils.SendMessage(GetString("KickCommandKickMod"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("KickCommandKickMod"), localPlayerId); break; } @@ -326,7 +327,7 @@ internal class ChatCommands canceled = true; if (GameStates.IsLobby) { - Utils.SendMessage(GetString("Message.CanNotUseInLobby"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.CanNotUseInLobby"), localPlayerId); break; } if (args.Length < 2 || !int.TryParse(args[1], out int id)) break; @@ -346,7 +347,7 @@ internal class ChatCommands canceled = true; if (GameStates.IsLobby) { - Utils.SendMessage(GetString("Message.CanNotUseInLobby"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.CanNotUseInLobby"), localPlayerId); break; } if (args.Length < 2 || !int.TryParse(args[1], out int id2)) break; @@ -364,41 +365,41 @@ internal class ChatCommands canceled = true; if (GameStates.IsInGame) { - Utils.SendMessage(GetString("Message.OnlyCanUseInLobby"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.OnlyCanUseInLobby"), localPlayerId); break; } subArgs = args.Length < 2 ? string.Empty : args[1]; var color = Utils.MsgToColor(subArgs, true); if (color == byte.MaxValue) { - Utils.SendMessage(GetString("IllegalColor"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("IllegalColor"), localPlayerId); break; } PlayerControl.LocalPlayer.RpcSetColor(color); - Utils.SendMessage(string.Format(GetString("Message.SetColor"), subArgs), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(string.Format(GetString("Message.SetColor"), subArgs), localPlayerId); break; case "/quit": case "/qt": canceled = true; - Utils.SendMessage(GetString("Message.CanNotUseByHost"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.CanNotUseByHost"), localPlayerId); break; case "/xf": canceled = true; if (!GameStates.IsInGame) { - Utils.SendMessage(GetString("Message.CanNotUseInLobby"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.CanNotUseInLobby"), localPlayerId); break; } - for (int i = 0; i < Main.AllPlayerControls.Count; i++) + for (int i = 0; i < Main.AllAlivePlayerControls.Count; i++) { - PlayerControl pc = Main.AllPlayerControls[i]; + PlayerControl pc = Main.AllAlivePlayerControls[i]; pc.RpcSetNameEx(pc.GetRealName(isMeeting: true)); } ChatUpdatePatch.DoBlockChat = false; Utils.NotifyRoles(isForMeeting: GameStates.IsMeeting, NoCache: true); - Utils.SendMessage(GetString("Message.TryFixName"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("Message.TryFixName"), localPlayerId); break; case "/id": @@ -410,14 +411,14 @@ internal class ChatCommands msgText += "\n" + pc.PlayerId.ToString() + " → " + Main.AllPlayerNames[pc.PlayerId]; } - Utils.SendMessage(msgText, PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(msgText, localPlayerId); break; /* case "/qq": canceled = true; if (Main.newLobby) Cloud.ShareLobby(true); - else Utils.SendMessage("很抱歉,每个房间车队姬只会发一次", PlayerControl.LocalPlayer.PlayerId); + else Utils.SendMessage("很抱歉,每个房间车队姬只会发一次", localPlayerId); break; */ @@ -473,58 +474,60 @@ internal class ChatCommands canceled = true; subArgs = text.Remove(0, 3); if (args.Length < 1 || !int.TryParse(args[1], out int sound1)) break; - RPC.PlaySoundRPC(PlayerControl.LocalPlayer.PlayerId, (Sounds)sound1); + RPC.PlaySoundRPC(localPlayerId, (Sounds)sound1); break; case "/gno": canceled = true; if (!GameStates.IsLobby && PlayerControl.LocalPlayer.IsAlive()) { - Utils.SendMessage(GetString("GNoCommandInfo"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("GNoCommandInfo"), localPlayerId); break; } subArgs = args.Length != 2 ? "" : args[1]; if (subArgs == "" || !int.TryParse(subArgs, out int guessedNo)) { - Utils.SendMessage(GetString("GNoCommandInfo"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("GNoCommandInfo"), localPlayerId); break; } else if (guessedNo < 0 || guessedNo > 99) { - Utils.SendMessage(GetString("GNoCommandInfo"), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(GetString("GNoCommandInfo"), localPlayerId); break; } else { - int targetNumber = Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][0]; - if (Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][0] == -1) + int targetNumber = Main.GuessNumber[localPlayerId][0]; + if (Main.GuessNumber[localPlayerId][0] == -1) { var rand = IRandom.Instance; - Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][0] = rand.Next(0, 100); - targetNumber = Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][0]; + Main.GuessNumber[localPlayerId][0] = rand.Next(0, 100); + targetNumber = Main.GuessNumber[localPlayerId][0]; } - Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][1]--; - if (Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][1] == 0) + Main.GuessNumber[localPlayerId][1]--; + if (Main.GuessNumber[localPlayerId][1] == 0 && guessedNo != targetNumber) { - Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][0] = -1; - Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][1] = 7; - //targetNumber = Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][0]; - Utils.SendMessage(string.Format(GetString("GNoLost"), targetNumber), PlayerControl.LocalPlayer.PlayerId); + Main.GuessNumber[localPlayerId][0] = -1; + Main.GuessNumber[localPlayerId][1] = 7; + //targetNumber = Main.GuessNumber[localPlayerId][0]; + Utils.SendMessage(string.Format(GetString("GNoLost"), targetNumber), localPlayerId); break; } else if (guessedNo < targetNumber) { - Utils.SendMessage(string.Format(GetString("GNoLow"), Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][1] - 1), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(string.Format(GetString("GNoLow"), Main.GuessNumber[localPlayerId][1]), localPlayerId); break; } else if (guessedNo > targetNumber) { - Utils.SendMessage(string.Format(GetString("GNoHigh"), Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][1] - 1), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(string.Format(GetString("GNoHigh"), Main.GuessNumber[localPlayerId][1]), localPlayerId); break; } else { - Utils.SendMessage(string.Format(GetString("GNoWon"), Main.GuessNumber[PlayerControl.LocalPlayer.PlayerId][1] - 1), PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage(string.Format(GetString("GNoWon"), Main.GuessNumber[localPlayerId][1]), localPlayerId); + Main.GuessNumber[localPlayerId][0] = -1; + Main.GuessNumber[localPlayerId][1] = 7; break; } @@ -1013,7 +1016,7 @@ internal class ChatCommands neutralnum++; } } - Utils.SendMessage($"There {(impnum == 1 ? "is" : "are")}\n{impnum} {(impnum == 1 ? "Impostor" : "Impostors")} and {neutralnum} {(neutralnum == 1 ? "Neutral Killer" : "Neutral Killers")} left.", PlayerControl.LocalPlayer.PlayerId); + Utils.SendMessage($"There {(impnum == 1 ? "is" : "are")}\n{impnum} {(impnum == 1 ? "Impostor" : "Impostors")} and {neutralnum} {(neutralnum == 1 ? "Neutral Killer" : "Neutral Killers")} left.", player.PlayerId); break; case "/gno": @@ -1044,7 +1047,7 @@ internal class ChatCommands targetNumber = Main.GuessNumber[player.PlayerId][0]; } Main.GuessNumber[player.PlayerId][1]--; - if (Main.GuessNumber[player.PlayerId][1] == 0) + if (Main.GuessNumber[player.PlayerId][1] == 0 && guessedNo != targetNumber) { Main.GuessNumber[player.PlayerId][0] = -1; Main.GuessNumber[player.PlayerId][1] = 7; @@ -1054,17 +1057,19 @@ internal class ChatCommands } else if (guessedNo < targetNumber) { - Utils.SendMessage(string.Format(GetString("GNoLow"), Main.GuessNumber[player.PlayerId][1] - 1), player.PlayerId); + Utils.SendMessage(string.Format(GetString("GNoLow"), Main.GuessNumber[player.PlayerId][1]), player.PlayerId); break; } else if (guessedNo > targetNumber) { - Utils.SendMessage(string.Format(GetString("GNoHigh"), Main.GuessNumber[player.PlayerId][1] - 1), player.PlayerId); + Utils.SendMessage(string.Format(GetString("GNoHigh"), Main.GuessNumber[player.PlayerId][1]), player.PlayerId); break; } else { - Utils.SendMessage(string.Format(GetString("GNoWon"), 7 - Main.GuessNumber[player.PlayerId][1] - 1), player.PlayerId); + Utils.SendMessage(string.Format(GetString("GNoWon"), 7 - Main.GuessNumber[player.PlayerId][1]), player.PlayerId); + Main.GuessNumber[player.PlayerId][0] = -1; + Main.GuessNumber[player.PlayerId][1] = 7; break; } } diff --git a/Patches/CheckGameEndPatch.cs b/Patches/CheckGameEndPatch.cs index fef27a014..31599f210 100644 --- a/Patches/CheckGameEndPatch.cs +++ b/Patches/CheckGameEndPatch.cs @@ -400,7 +400,7 @@ class GameEndChecker int Imp = AlivePlayersCount(CountTypes.Impostor); int Crew = AlivePlayersCount(CountTypes.Crew); - Dictionary<(CustomRoles?, CustomWinner), int> roleCounts = new() + Dictionary<(CustomRoles?, CustomWinner), int> roleCounts = new() // Self Note: If you're adding a new NK, you just have to add it into this dictionary and that's it { { (null, CustomWinner.Jackal), AlivePlayersCount(CountTypes.Jackal) }, { (CustomRoles.Pelican, CustomWinner.Pelican), AlivePlayersCount(CountTypes.Pelican) }, @@ -500,6 +500,7 @@ class GameEndChecker if (aliveCounts.Count > 1) return false; // There are multiple types of NKs alive, game must continue else if (aliveCounts.Count == 1) // There is only one type of NK alive, they've won { + if (aliveCounts[0] != roleCounts.Values.Max()) Logger.Warn("There is something wrong here.", "CheckGameEndPatch"); foreach (var keyValuePair in roleCounts.Where(keyValuePair => keyValuePair.Value == aliveCounts[0])) { reason = GameOverReason.ImpostorByKill; diff --git a/Patches/ControlPatch.cs b/Patches/ControlPatch.cs index 6a5ca591a..f6bf20b90 100644 --- a/Patches/ControlPatch.cs +++ b/Patches/ControlPatch.cs @@ -297,7 +297,7 @@ internal class ControllerManagerUpdatePatch { if (keys.Any(Input.GetKeyDown) && keys.All(Input.GetKey)) { - Logger.Info($"快捷键:{keys.Where(Input.GetKeyDown).First()} in [{string.Join(",", keys)}]", "GetKeysDown"); + Logger.Info($"Shortcut Key:{keys.Where(Input.GetKeyDown).First()} in [{string.Join(",", keys)}]", "GetKeysDown"); return true; } return false; diff --git a/Patches/ExilePatch.cs b/Patches/ExilePatch.cs index 6a09a531c..74984b940 100644 --- a/Patches/ExilePatch.cs +++ b/Patches/ExilePatch.cs @@ -207,7 +207,7 @@ class ExileControllerWrapUpPatch GameStates.AlreadyDied |= !Utils.IsAllAlive; RemoveDisableDevicesPatch.UpdateDisableDevices(); SoundManager.Instance.ChangeAmbienceVolume(DataManager.Settings.Audio.AmbienceVolume); - Logger.Info("タスクフェイズ開始", "Phase"); + Logger.Info("Start task phase", "Phase"); } } diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index e36070b8c..ba8579d44 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -347,7 +347,8 @@ class HudManagerPatch __instance.KillButton?.OverrideText(GetString("TotocalcioKillButtonText")); break; case CustomRoles.Romantic: - __instance.KillButton?.OverrideText(GetString("RomanticKillButtonText")); + if (Romantic.BetTimes.TryGetValue(player.PlayerId, out var timesV1) && timesV1 >= 1) __instance.KillButton?.OverrideText(GetString("RomanticKillButtonText")); + else __instance.KillButton?.OverrideText(GetString("MedicalerButtonText")); break; case CustomRoles.VengefulRomantic: __instance.KillButton?.OverrideText(GetString("VengefulRomanticKillButtonText")); diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs index e31b6c696..749758a57 100644 --- a/Patches/IntroPatch.cs +++ b/Patches/IntroPatch.cs @@ -538,7 +538,6 @@ class IntroCutsceneDestroyPatch { try { - pc.RpcShapeshift(Utils.GetPlayerById(0), false); pc.RpcShapeshift(pc, false); pc.Notify("", 0.1f); } diff --git a/Patches/MainMenuManagerPatch.cs b/Patches/MainMenuManagerPatch.cs index 73c08d6ba..58a960428 100644 --- a/Patches/MainMenuManagerPatch.cs +++ b/Patches/MainMenuManagerPatch.cs @@ -102,7 +102,7 @@ public class MainMenuManagerPatch { freeplayButton.GetComponent().OnClick = new(); freeplayButton.GetComponent().OnClick.AddListener((Action)(() => Application.OpenURL("https://tohe.cc"))); - __instance.StartCoroutine(Effects.Lerp(0.01f, new Action((p) => freeplayButton.transform.GetChild(0).GetComponent().SetText(GetString("Website"))))); + __instance.StartCoroutine(Effects.Lerp(0.01f, new Action((p) => freeplayButton.transform.GetChild(0).GetComponent().SetText(GetString("Website"))))); } #endif diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index be7fd819d..7ddd01725 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -36,9 +36,9 @@ class CheckForEndVotingPatch if (pva == null) continue; PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); if (pc == null) continue; - //死んでいないディクテーターが投票済み + // Dictators who are not dead have already voted. - //主动叛变 + // Take the initiative to rebel if (pva.DidVote && pc.PlayerId == pva.VotedFor && pva.VotedFor < 253 && !pc.Data.IsDead) { if (Options.MadmateSpawnMode.GetInt() == 2 && Main.MadmateNum < CustomRoles.Madmate.GetCount() && Utils.CanBeMadmate(pc)) @@ -47,11 +47,11 @@ class CheckForEndVotingPatch pc.RpcSetCustomRole(CustomRoles.Madmate); ExtendedPlayerControl.RpcSetCustomRole(pc.PlayerId, CustomRoles.Madmate); Utils.NotifyRoles(true, pc, true); - Logger.Info("设置职业:" + pc?.Data?.PlayerName + " = " + pc.GetCustomRole().ToString() + " + " + CustomRoles.Madmate.ToString(), "Assign " + CustomRoles.Madmate.ToString()); + Logger.Info("Set role: " + pc?.Data?.PlayerName + " => " + pc.GetCustomRole().ToString() + " + " + CustomRoles.Madmate.ToString(), "Assign " + CustomRoles.Madmate.ToString()); } } - //催眠师催眠 + // hypnotist hypnosis if (pc.Is(CustomRoles.Dictator) && pva.DidVote && pc.PlayerId != pva.VotedFor && pva.VotedFor < 253 && !pc.Data.IsDead) { @@ -68,11 +68,11 @@ class CheckForEndVotingPatch __instance.RpcVotingComplete(states.ToArray(), null, true); ExileControllerWrapUpPatch.AntiBlackout_LastExiled = voteTarget.Data; } - else __instance.RpcVotingComplete(states.ToArray(), voteTarget.Data, false); //通常処理 + else __instance.RpcVotingComplete(states.ToArray(), voteTarget.Data, false); // Normal processing - Logger.Info($"{voteTarget.GetNameWithRole().RemoveHtmlTags()} 被独裁者驱逐", "Dictator"); + Logger.Info($"{voteTarget.GetNameWithRole().RemoveHtmlTags()} expelled by dictator", "Dictator"); CheckForDeathOnExile(PlayerState.DeathReason.Vote, pva.VotedFor); - Logger.Info("独裁投票,会议强制结束", "Special Phase"); + Logger.Info("Dictatorship vote, forced end of meeting", "Special Phase"); voteTarget.SetRealKiller(pc); Main.LastVotedPlayerInfo = voteTarget.Data; if (Main.LastVotedPlayerInfo != null) @@ -128,7 +128,7 @@ class CheckForEndVotingPatch PlayerVoteArea ps = __instance.playerStates[i]; if (shouldSkip) break; //Meeting Skip with vote counting on keystroke (m + delete) - //死んでいないプレイヤーが投票していない + // Non-dead players are not voting if (!(Main.PlayerStates[ps.TargetPlayerId].IsDead || ps.DidVote)) return false; } @@ -154,11 +154,11 @@ class CheckForEndVotingPatch { case VoteMode.Suicide: TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.Suicide, ps.TargetPlayerId); - voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()}因跳过投票自杀"); + voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()} Commit suicide for skipping voting"); break; case VoteMode.SelfVote: ps.VotedFor = ps.TargetPlayerId; - voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()}因跳过投票自票"); + voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()} Self-voting due to skipping voting"); break; default: break; @@ -170,15 +170,15 @@ class CheckForEndVotingPatch { case VoteMode.Suicide: TryAddAfterMeetingDeathPlayers(PlayerState.DeathReason.Suicide, ps.TargetPlayerId); - voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()}因未投票自杀"); + voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()} Committed suicide for not voting"); break; case VoteMode.SelfVote: ps.VotedFor = ps.TargetPlayerId; - voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()}因未投票自票"); + voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()} Self-voting due to not voting"); break; case VoteMode.Skip: ps.VotedFor = 253; - voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()}因未投票跳过"); + voteLog.Info($"{voter.GetNameWithRole().RemoveHtmlTags()} Skip for not voting"); break; default: break; @@ -252,8 +252,8 @@ class CheckForEndVotingPatch var voteAreaPlayer = Utils.GetPlayerById(playerVoteArea.TargetPlayerId); if (NiceList1.Contains(voteAreaPlayer.PlayerId)) continue; playerVoteArea.UnsetVote(); - playerVoteArea.VotedFor = swap1.PlayerId; meetingHud.CastVote(voteAreaPlayer.PlayerId, swap1.PlayerId); + playerVoteArea.VotedFor = swap1.PlayerId; } if (Main.NiceSwapSend == false) { @@ -294,27 +294,27 @@ class CheckForEndVotingPatch var VotingData = __instance.CustomCalculateVotes(); byte exileId = byte.MaxValue; int max = 0; - voteLog.Info("===决定驱逐玩家处理开始==="); + voteLog.Info("===Decision to expel player processing begins==="); foreach (var data in VotingData) { voteLog.Info($"{data.Key}({Utils.GetVoteName(data.Key)}):{data.Value}票"); if (data.Value > max) { - voteLog.Info(data.Key + "拥有更高票数(" + data.Value + ")"); + voteLog.Info(data.Key + " has higher votes (" + data.Value + ")"); exileId = data.Key; max = data.Value; tie = false; } else if (data.Value == max) { - voteLog.Info(data.Key + "与" + exileId + "的票数相同(" + data.Value + ")"); + voteLog.Info(data.Key + " and " + exileId + "have the same number of votes (" + data.Value + ")"); exileId = byte.MaxValue; tie = true; } - voteLog.Info($"驱逐ID: {exileId}, 最大: {max}票"); + voteLog.Info($"expelID: {exileId}, maximum: {max} votes"); } - voteLog.Info($"决定驱逐玩家: {exileId}({Utils.GetVoteName(exileId)})"); + voteLog.Info($"Decide to evict player: {exileId} ({Utils.GetVoteName(exileId)})"); bool braked = false; if (tie) //破平者判断 @@ -334,7 +334,7 @@ class CheckForEndVotingPatch } if (target != byte.MaxValue) { - Logger.Info("破平者覆盖驱逐玩家", "Brakar Vote"); + Logger.Info("Tiebreaker overrides evicted players", "Brakar Vote"); exiledPlayer = Utils.GetPlayerInfoById(target); tie = false; braked = true; @@ -523,13 +523,13 @@ class CheckForEndVotingPatch _ = new LateTask(() => { Main.DoBlockNameChange = true; - if (GameStates.IsInGame) player.RpcSetName(name); + if (GameStates.IsInGame) player?.RpcSetName(name); }, 3.0f, "Change Exiled Player Name"); _ = new LateTask(() => { if (GameStates.IsInGame && !player.Data.Disconnected) { - player.RpcSetName(realName); + player?.RpcSetName(realName); Main.DoBlockNameChange = false; } }, 11.5f, "Change Exiled Player Name Back"); @@ -597,7 +597,7 @@ static class ExtendedMeetingHud { public static Dictionary CustomCalculateVotes(this MeetingHud __instance) { - Logger.Info("===计算票数处理开始===", "Vote"); + Logger.Info("===The vote counting process begins===", "Vote"); Dictionary dic = new(); Main.BrakarVoteFor = new(); Collector.CollectorVoteFor = new(); @@ -799,7 +799,7 @@ class MeetingHudStartPatch } public static void Prefix(/*MeetingHud __instance*/) { - Logger.Info("------------会议开始------------", "Phase"); + Logger.Info("------------Meeting Start------------", "Phase"); ChatUpdatePatch.DoBlockChat = true; GameStates.AlreadyDied |= !Utils.IsAllAlive; Main.AllPlayerControls.Do(x => ReportDeadBodyPatch.WaitReport[x.PlayerId].Clear()); @@ -1281,7 +1281,7 @@ class MeetingHudOnDestroyPatch public static void Postfix() { MeetingStates.FirstMeeting = false; - Logger.Info("------------会议结束------------", "Phase"); + Logger.Info("------------End of meeting------------", "Phase"); if (AmongUsClient.Instance.AmHost) { AntiBlackout.SetIsDead(); @@ -1291,4 +1291,62 @@ class MeetingHudOnDestroyPatch EAC.MeetingTimes = 0; } } +} +[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.CastVote))] +class MeetingHudCastVotePatch +{ + public static bool Prefix() + { + return true; // return true to use the vote as a trigger + } + public static void Postfix(MeetingHud __instance, [HarmonyArgument(0)] byte srcPlayerId, [HarmonyArgument(1)] byte suspectPlayerId) + { + PlayerVoteArea pva_src = null; + PlayerVoteArea pva_target = null; + bool isSkip = false; + for (int i = 0; i < __instance.playerStates.Count; i++) + { + if (__instance.playerStates[i].TargetPlayerId == srcPlayerId) pva_src = __instance.playerStates[i]; + if (__instance.playerStates[i].TargetPlayerId == suspectPlayerId) pva_target = __instance.playerStates[i]; + } + if (pva_src == null) + { + Logger.Error("Src PlayerVoteArea not found", "MeetingHudCastVotePatch.Prefix"); + return; + } + if (pva_target == null) + { + //Logger.Warn("Target PlayerVoteArea not found => Vote treated as a Skip", "MeetingHudCastVotePatch.Prefix"); + isSkip = true; + } + var pc_src = Utils.GetPlayerById(srcPlayerId); + var pc_target = Utils.GetPlayerById(suspectPlayerId); + if (pc_src == null) + { + Logger.Error("Src PlayerControl is null", "MeetingHudCastVotePatch.Prefix"); + return; + } + if (pc_target == null) + { + //Logger.Warn("Target PlayerControl is null => Vote treated as a Skip", "MeetingHudCastVotePatch.Prefix"); + isSkip = true; + } + + Logger.Info($"{pc_src.GetNameWithRole().RemoveHtmlTags()} => {(isSkip ? "Skip" : pc_target.GetNameWithRole().RemoveHtmlTags())}", "Vote"); + + //pva_src.UnsetVote(); // Uncomment to use the vote as a trigger + //__instance.RpcClearVote(pc_src.GetClientId()); // Uncomment to use the vote as a trigger + } +} +[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.CmdCastVote))] +class MeetingHudCmdCastVotePatch +{ + public static bool Prefix() + { + return MeetingHudCastVotePatch.Prefix(); + } + public static void Postfix(MeetingHud __instance, [HarmonyArgument(0)] byte srcPlayerId, [HarmonyArgument(1)] byte suspectPlayerId) + { + MeetingHudCastVotePatch.Postfix(__instance, srcPlayerId, suspectPlayerId); + } } \ No newline at end of file diff --git a/Patches/PetActionsPatch.cs b/Patches/PetActionsPatch.cs index 93bb50b94..488dbb729 100644 --- a/Patches/PetActionsPatch.cs +++ b/Patches/PetActionsPatch.cs @@ -1,5 +1,4 @@ using HarmonyLib; -using Hazel; using System; using System.Linq; using TOHE.Modules; @@ -32,10 +31,10 @@ class LocalPetPatch if (!LastProcess.ContainsKey(__instance.PlayerId)) LastProcess.TryAdd(__instance.PlayerId, Utils.GetTimeStamp() - 2); if (LastProcess[__instance.PlayerId] + 1 >= Utils.GetTimeStamp()) return true; - ExternalRpcPetPatch.Prefix(__instance.MyPhysics, 51); + ExternalRpcPetPatch.Prefix(__instance.MyPhysics, (byte)RpcCalls.Pet); LastProcess[__instance.PlayerId] = Utils.GetTimeStamp(); - return false; + return !__instance.GetCustomRole().PetActivatedAbility(); } public static void Postfix(PlayerControl __instance) @@ -49,31 +48,44 @@ class LocalPetPatch [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.HandleRpc))] class ExternalRpcPetPatch { - public static void Prefix(PlayerPhysics __instance, [HarmonyArgument(0)] byte callId) + public static void Prefix(PlayerPhysics __instance, [HarmonyArgument(0)] byte callID) { - if (!Options.UsePets.GetBool()) return; - if (!AmongUsClient.Instance.AmHost) return; - var rpcType = callId == 51 ? RpcCalls.Pet : (RpcCalls)callId; - if (rpcType != RpcCalls.Pet) return; + if (!Options.UsePets.GetBool() || !AmongUsClient.Instance.AmHost || (RpcCalls)callID != RpcCalls.Pet) return; - PlayerControl pc = __instance.myPlayer; + var pc = __instance.myPlayer; + var physics = __instance; - if (callId == 51 && pc.GetCustomRole().PetActivatedAbility() && GameStates.IsInGame) __instance.CancelPet(); - if (callId != 51) - { - if (AmongUsClient.Instance.AmHost && pc.GetCustomRole().PetActivatedAbility() && GameStates.IsInGame) - __instance.CancelPet(); - foreach (PlayerControl player in PlayerControl.AllPlayerControls) - AmongUsClient.Instance.FinishRpcImmediately(AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, 50, SendOption.None, player.GetClientId())); - } + if (pc == null || physics == null) return; + + if (pc != null + && !pc.inVent + && !pc.inMovingPlat + && !pc.walkingToVent + && !pc.onLadder + && !physics.Animations.IsPlayingEnterVentAnimation() + && !physics.Animations.IsPlayingClimbAnimation() + && !physics.Animations.IsPlayingAnyLadderAnimation() + && !Pelican.IsEaten(pc.PlayerId) + && GameStates.IsInTask + && pc.GetCustomRole().PetActivatedAbility()) + physics.CancelPet(); Logger.Info($"Player {pc.GetNameWithRole().RemoveHtmlTags()} petted their pet", "PetActionTrigger"); - OnPetUse(pc); + _ = new LateTask(() => { OnPetUse(pc); }, 0.2f, $"OnPetUse: {pc.GetNameWithRole().RemoveHtmlTags()}", false); } public static void OnPetUse(PlayerControl pc) { - if (pc == null) return; + if (pc == null || + pc.inVent || + pc.inMovingPlat || + pc.onLadder || + pc.walkingToVent || + pc.MyPhysics.Animations.IsPlayingEnterVentAnimation() || + pc.MyPhysics.Animations.IsPlayingClimbAnimation() || + pc.MyPhysics.Animations.IsPlayingAnyLadderAnimation() || + Pelican.IsEaten(pc.PlayerId)) + return; switch (pc.GetCustomRole()) { diff --git a/Patches/PlayerContorolPatch.cs b/Patches/PlayerContorolPatch.cs index fea1ec63e..85553f1cb 100644 --- a/Patches/PlayerContorolPatch.cs +++ b/Patches/PlayerContorolPatch.cs @@ -14,6 +14,7 @@ using TOHE.Roles.Impostor; using TOHE.Roles.Neutral; using UnityEngine; using static TOHE.Translator; +using static TOHE.Utils; namespace TOHE; @@ -306,6 +307,7 @@ class CheckMurderPatch if (!Poisoner.OnCheckMurder(killer, target)) return false; break; case CustomRoles.Warlock: + if (!Main.isCurseAndKill.ContainsKey(killer.PlayerId)) Main.isCurseAndKill[killer.PlayerId] = false; if (!Main.CheckShapeshift[killer.PlayerId] && !Main.isCurseAndKill[killer.PlayerId]) { //Warlockが変身時以外にキルしたら、呪われる処理 if (target.Is(CustomRoles.Needy) || target.Is(CustomRoles.Lazy)) return false; @@ -353,7 +355,7 @@ class CheckMurderPatch Main.PuppeteerList[target.PlayerId] = killer.PlayerId; killer.SetKillCooldown(); killer.RPCPlayCustomSound("Line"); - Utils.NotifyRoles(SpecifySeer: killer); + NotifyRoles(SpecifySeer: killer); return false; //case CustomRoles.NWitch: // // if (target.Is(CustomRoles.Needy) || target.Is(CustomRoles.Lazy)) return false; @@ -436,7 +438,7 @@ class CheckMurderPatch if (!Main.isDoused[(killer.PlayerId, target.PlayerId)] && !Main.ArsonistTimer.ContainsKey(killer.PlayerId)) { Main.ArsonistTimer.Add(killer.PlayerId, (target, 0f)); - Utils.NotifyRoles(SpecifySeer: __instance); + NotifyRoles(SpecifySeer: __instance); RPC.SetCurrentDousingTarget(killer.PlayerId, target.PlayerId); } return false; @@ -445,7 +447,7 @@ class CheckMurderPatch if (!Main.isDraw[(killer.PlayerId, target.PlayerId)] && !Main.RevolutionistTimer.ContainsKey(killer.PlayerId)) { Main.RevolutionistTimer.TryAdd(killer.PlayerId, (target, 0f)); - Utils.NotifyRoles(SpecifySeer: __instance); + NotifyRoles(SpecifySeer: __instance); RPC.SetCurrentDrawTarget(killer.PlayerId, target.PlayerId); } return false; @@ -454,7 +456,7 @@ class CheckMurderPatch if (!Main.isRevealed[(killer.PlayerId, target.PlayerId)] && !Main.FarseerTimer.ContainsKey(killer.PlayerId)) { Main.FarseerTimer.TryAdd(killer.PlayerId, (target, 0f)); - Utils.NotifyRoles(SpecifySeer: __instance); + NotifyRoles(SpecifySeer: __instance); RPC.SetCurrentRevealTarget(killer.PlayerId, target.PlayerId); } return false; @@ -610,13 +612,13 @@ class CheckMurderPatch { if (!target.Is(CustomRoles.Pestilence)) { - Utils.TP(target.NetTransform, Pelican.GetBlackRoomPS()); + TP(target.NetTransform, Pelican.GetBlackRoomPS()); target.SetRealKiller(killer); Main.PlayerStates[target.PlayerId].SetDead(); target.Kill(target); killer.SetKillCooldown(); RPC.PlaySoundRPC(killer.PlayerId, Sounds.KillSound); - NameNotifyManager.Notify(target, Utils.ColorString(Utils.GetRoleColor(CustomRoles.Scavenger), GetString("KilledByScavenger"))); + NameNotifyManager.Notify(target, ColorString(GetRoleColor(CustomRoles.Scavenger), GetString("KilledByScavenger"))); return false; } if (target.Is(CustomRoles.Pestilence)) @@ -663,7 +665,7 @@ class CheckMurderPatch messageWriter.Write((byte)ExtendedPlayerControl.ResultFlags); AmongUsClient.Instance.FinishRpcImmediately(messageWriter); } - Utils.TP(killer.NetTransform, ops); + TP(killer.NetTransform, ops); }, 0.05f, "OverKiller Murder"); } @@ -855,7 +857,7 @@ class CheckMurderPatch //击杀老兵 case CustomRoles.Veteran: if (Main.VeteranInProtect.ContainsKey(target.PlayerId) && killer.PlayerId != target.PlayerId) - if (Main.VeteranInProtect[target.PlayerId] + Options.VeteranSkillDuration.GetInt() >= Utils.GetTimeStamp()) + if (Main.VeteranInProtect[target.PlayerId] + Options.VeteranSkillDuration.GetInt() >= GetTimeStamp()) { if (!killer.Is(CustomRoles.Pestilence)) { @@ -875,7 +877,7 @@ class CheckMurderPatch break; case CustomRoles.TimeMaster: if (Main.TimeMasterInProtect.ContainsKey(target.PlayerId) && killer.PlayerId != target.PlayerId) - if (Main.TimeMasterInProtect[target.PlayerId] + Options.TimeMasterSkillDuration.GetInt() >= Utils.GetTimeStamp(DateTime.UtcNow)) + if (Main.TimeMasterInProtect[target.PlayerId] + Options.TimeMasterSkillDuration.GetInt() >= GetTimeStamp(DateTime.UtcNow)) { for (int i = 0; i < Main.AllPlayerControls.Count; i++) { @@ -885,7 +887,7 @@ class CheckMurderPatch if (Main.TimeMasterBackTrack.ContainsKey(player.PlayerId)) { var position = Main.TimeMasterBackTrack[player.PlayerId]; - Utils.TP(player.NetTransform, position); + TP(player.NetTransform, position); } } } @@ -974,7 +976,7 @@ class CheckMurderPatch } //首刀保护 - if (Main.ShieldPlayer != byte.MaxValue && Main.ShieldPlayer == target.PlayerId && Utils.IsAllAlive) + if (Main.ShieldPlayer != byte.MaxValue && Main.ShieldPlayer == target.PlayerId && IsAllAlive) { Main.ShieldPlayer = byte.MaxValue; killer.SetKillCooldown(15f); @@ -990,7 +992,7 @@ class CheckMurderPatch Main.MadmateNum++; target.RpcSetCustomRole(CustomRoles.Madmate); ExtendedPlayerControl.RpcSetCustomRole(target.PlayerId, CustomRoles.Madmate); - target.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Madmate), GetString("BecomeMadmateCuzMadmateMode"))); + target.Notify(ColorString(GetRoleColor(CustomRoles.Madmate), GetString("BecomeMadmateCuzMadmateMode"))); killer.SetKillCooldown(); killer.RpcGuardAndKill(target); target.RpcGuardAndKill(killer); @@ -1036,7 +1038,7 @@ class MurderPlayerPatch if (killer.Is(CustomRoles.Sniper)) if (!Options.UsePets.GetBool()) killer.RpcResetAbilityCooldown(); - else Main.SniperCD.TryAdd(killer.PlayerId, Utils.GetTimeStamp()); + else Main.SniperCD.TryAdd(killer.PlayerId, GetTimeStamp()); if (killer != __instance) { @@ -1073,7 +1075,7 @@ class MurderPlayerPatch // VengefulRomantic.PartnerKiller.Add(killer.PlayerId, 1); Main.AllKillers.Remove(killer.PlayerId); - Main.AllKillers.Add(killer.PlayerId, Utils.GetTimeStamp()); + Main.AllKillers.Add(killer.PlayerId, GetTimeStamp()); switch (target.GetCustomRole()) { @@ -1166,14 +1168,14 @@ class MurderPlayerPatch if (Options.BaitDelayMax.GetFloat() < Options.BaitDelayMin.GetFloat()) delay = 0f; else delay = IRandom.Instance.Next((int)Options.BaitDelayMin.GetFloat(), (int)Options.BaitDelayMax.GetFloat() + 1); delay = Math.Max(delay, 0.15f); - if (delay > 0.15f && Options.BaitDelayNotify.GetBool()) killer.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Bait), string.Format(GetString("KillBaitNotify"), (int)delay)), delay); + if (delay > 0.15f && Options.BaitDelayNotify.GetBool()) killer.Notify(ColorString(GetRoleColor(CustomRoles.Bait), string.Format(GetString("KillBaitNotify"), (int)delay)), delay); Logger.Info($"{killer.GetNameWithRole().RemoveHtmlTags()} 击杀诱饵 => {target.GetNameWithRole().RemoveHtmlTags()}", "MurderPlayer"); _ = new LateTask(() => { if (GameStates.IsInTask) killer.CmdReportDeadBody(target.Data); }, delay, "Bait Self Report"); } } foreach (var pc in Main.AllAlivePlayerControls.Where(x => x.Is(CustomRoles.Mediumshiper))) - pc.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Mediumshiper), GetString("MediumshiperKnowPlayerDead"))); + pc.Notify(ColorString(GetRoleColor(CustomRoles.Mediumshiper), GetString("MediumshiperKnowPlayerDead"))); if (Executioner.Target.ContainsValue(target.PlayerId)) Executioner.ChangeRoleByTarget(target); @@ -1185,29 +1187,53 @@ class MurderPlayerPatch if (Tracefinder.IsEnable) Tracefinder.OnPlayerDead(target); if (Vulture.IsEnable) Vulture.OnPlayerDead(target); - Utils.AfterPlayerDeathTasks(target); + AfterPlayerDeathTasks(target); Main.PlayerStates[target.PlayerId].SetDead(); target.SetRealKiller(killer, true); //既に追加されてたらスキップ - Utils.CountAlivePlayers(true); + CountAlivePlayers(true); Camouflager.IsDead(target); - Utils.TargetDies(__instance, target); + TargetDies(__instance, target); if (Options.LowLoadMode.GetBool()) { __instance.MarkDirtySettings(); target.MarkDirtySettings(); - Utils.NotifyRoles(SpecifySeer: killer); - Utils.NotifyRoles(SpecifySeer: target); + NotifyRoles(SpecifySeer: killer); + NotifyRoles(SpecifySeer: target); } else { - Utils.SyncAllSettings(); - Utils.NotifyRoles(); + SyncAllSettings(); + NotifyRoles(); } } } +[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CheckShapeshift))] +class CheckShapeshiftPatch +{ + public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) + { + Logger.Info($"Check Shapeshift Trigger - __instance: {__instance}, target: {target}, shouldAnimate: {shouldAnimate}", "Prefix"); + } + public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) + { + Logger.Info($"Check Shapeshift Trigger - __instance: {__instance}, target: {target}, shouldAnimate: {shouldAnimate}", "Postfix"); + } +} +[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CmdCheckShapeshift))] +class CmdCheckShapeshiftPatch +{ + public static void Prefix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) + { + CheckShapeshiftPatch.Prefix(__instance, target, shouldAnimate); + } + public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)] PlayerControl target, bool shouldAnimate) + { + CheckShapeshiftPatch.Postfix(__instance, target, shouldAnimate); + } +} [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.Shapeshift))] class ShapeshiftPatch { @@ -1315,7 +1341,7 @@ class ShapeshiftPatch var position = Main.EscapeeLocation[shapeshifter.PlayerId]; Main.EscapeeLocation.Remove(shapeshifter.PlayerId); Logger.Msg($"{shapeshifter.GetNameWithRole().RemoveHtmlTags()}:{position}", "EscapeeTeleport"); - Utils.TP(shapeshifter.NetTransform, position); + TP(shapeshifter.NetTransform, position); shapeshifter.RPCPlayCustomSound("Teleport"); } else @@ -1335,7 +1361,7 @@ class ShapeshiftPatch var vent = Main.LastEnteredVent[shapeshifter.PlayerId]; var position = Main.LastEnteredVentLocation[shapeshifter.PlayerId]; Logger.Msg($"{shapeshifter.GetNameWithRole().RemoveHtmlTags()}:{position}", "MinerTeleport"); - Utils.TP(shapeshifter.NetTransform, new Vector2(position.x, position.y)); + TP(shapeshifter.NetTransform, new Vector2(position.x, position.y)); } if (shapeshifting) { @@ -1375,7 +1401,7 @@ class ShapeshiftPatch { shapeshifter.CmdCheckRevertShapeshift(false); } - Utils.NotifyRoles(); + NotifyRoles(); }, 1.5f, "Bomber Suiscide"); } if (Options.BomberDiesInExplosion.GetBool()) isSSneeded = false; @@ -1413,7 +1439,7 @@ class ShapeshiftPatch { shapeshifter.CmdCheckRevertShapeshift(false); } - Utils.NotifyRoles(); + NotifyRoles(); }, 1.5f, "Nuke"); } isSSneeded = false; @@ -1436,8 +1462,8 @@ class ShapeshiftPatch if (!(!GameStates.IsInTask || !shapeshifter.IsAlive() || !target.IsAlive() || shapeshifter.inVent || target.inVent)) { var originPs = target.GetTruePosition(); - Utils.TP(target.NetTransform, shapeshifter.GetTruePosition()); - Utils.TP(shapeshifter.NetTransform, originPs); + TP(target.NetTransform, shapeshifter.GetTruePosition()); + TP(shapeshifter.NetTransform, originPs); } }, 1.5f, "ImperiusCurse TP"); } @@ -1503,7 +1529,7 @@ class ShapeshiftPatch { _ = new LateTask(() => { - Utils.NotifyRoles(NoCache: true); + NotifyRoles(NoCache: true); }, 1.2f, "ShapeShiftNotify"); } @@ -1537,7 +1563,7 @@ class ReportDeadBodyPatch foreach (var kvp in Main.PlayerStates) { - var pc = Utils.GetPlayerById(kvp.Key); + var pc = GetPlayerById(kvp.Key); kvp.Value.LastRoom = pc.GetPlainShipRoom(); } @@ -1558,7 +1584,7 @@ class ReportDeadBodyPatch //杀戮机器无法报告或拍灯 // if (__instance.Is(CustomRoles.Minimalism)) return false; //禁止小黑人报告 - if (((Utils.IsActive(SystemTypes.Comms) && Options.CommsCamouflage.GetBool() && (Main.NormalOptions.MapId != 5 || !Options.CommsCamouflageDisableOnFungle.GetBool())) || Camouflager.IsActive) && Options.DisableReportWhenCC.GetBool()) return false; + if (((IsActive(SystemTypes.Comms) && Options.CommsCamouflage.GetBool() && (Main.NormalOptions.MapId != 5 || !Options.CommsCamouflageDisableOnFungle.GetBool())) || Camouflager.IsActive) && Options.DisableReportWhenCC.GetBool()) return false; if (target == null) //拍灯事件 { @@ -1586,7 +1612,7 @@ class ReportDeadBodyPatch if (__instance.Is(CustomRoles.Vulture)) { - long now = Utils.GetTimeStamp(); + long now = GetTimeStamp(); if ((Vulture.AbilityLeftInRound[__instance.PlayerId] > 0) && (now - Vulture.LastReport[__instance.PlayerId] > (long)Vulture.VultureReportCD.GetFloat())) { Vulture.LastReport[__instance.PlayerId] = now; @@ -1650,7 +1676,7 @@ class ReportDeadBodyPatch if (Main.MedusaBodies.Contains(target.PlayerId)) return false; // 胆小鬼不敢报告 - var tpc = Utils.GetPlayerById(target.PlayerId); + var tpc = GetPlayerById(target.PlayerId); if (__instance.Is(CustomRoles.Oblivious)) { if (!tpc.Is(CustomRoles.Bait) || (tpc.Is(CustomRoles.Bait) && Options.ObliviousBaitImmune.GetBool())) /* && (target?.Object != null)*/ @@ -1678,7 +1704,7 @@ class ReportDeadBodyPatch { var killerID = Main.KillerOfBoobyTrapBody[target.PlayerId]; Main.PlayerStates[__instance.PlayerId].deathReason = PlayerState.DeathReason.Bombed; - __instance.SetRealKiller(Utils.GetPlayerById(killerID)); + __instance.SetRealKiller(GetPlayerById(killerID)); __instance.Kill(__instance); RPC.PlaySoundRPC(killerID, Sounds.KillSound); @@ -1691,7 +1717,7 @@ class ReportDeadBodyPatch { var killerID2 = target.PlayerId; Main.PlayerStates[__instance.PlayerId].deathReason = PlayerState.DeathReason.Bombed; - __instance.SetRealKiller(Utils.GetPlayerById(killerID2)); + __instance.SetRealKiller(GetPlayerById(killerID2)); __instance.Kill(__instance); RPC.PlaySoundRPC(killerID2, Sounds.KillSound); @@ -1743,7 +1769,7 @@ class ReportDeadBodyPatch } else { - var tpc = Utils.GetPlayerById(target.PlayerId); + var tpc = GetPlayerById(target.PlayerId); if (tpc != null && !tpc.IsAlive()) { // 侦探报告 @@ -1848,7 +1874,7 @@ class ReportDeadBodyPatch foreach (var x in Main.RevolutionistStart) { - var tar = Utils.GetPlayerById(x.Key); + var tar = GetPlayerById(x.Key); if (tar == null) continue; tar.Data.IsDead = true; Main.PlayerStates[tar.PlayerId].deathReason = PlayerState.DeathReason.Sacrifice; @@ -1866,9 +1892,9 @@ class ReportDeadBodyPatch MeetingTimeManager.OnReportDeadBody(); - Utils.NotifyRoles(isForMeeting: true, NoCache: true, CamouflageIsForMeeting: true, GuesserIsForMeeting: true); + NotifyRoles(isForMeeting: true, NoCache: true, CamouflageIsForMeeting: true, GuesserIsForMeeting: true); - _ = new LateTask(Utils.SyncAllSettings, 3f); + _ = new LateTask(SyncAllSettings, 3f); } public static async void ChangeLocalNameAndRevert(string name, int time) { @@ -1957,7 +1983,11 @@ class FixedUpdatePatch LocateArrow.OnFixedUpdate(player); } - if (!lowLoad && RPCHandlerPatch.ReportDeadBodyRPCs.ContainsKey(player.PlayerId)) RPCHandlerPatch.ReportDeadBodyRPCs.Remove(player.PlayerId); + if (!lowLoad) + { + if (RPCHandlerPatch.ReportDeadBodyRPCs.Remove(player.PlayerId)) + Logger.Info($"Cleared ReportDeadBodyRPC Count for {player.GetRealName().RemoveHtmlTags()}", "FixedUpdatePatch"); + } if (AmongUsClient.Instance.AmHost) {//実行クライアントがホストの場合のみ実行 @@ -2034,196 +2064,196 @@ class FixedUpdatePatch switch (player.GetCustomRole()) { case CustomRoles.Doormaster: - if (Main.DoormasterCD.TryGetValue(player.PlayerId, out var dm) && dm + Doormaster.VentCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.DoormasterCD.TryGetValue(player.PlayerId, out var dm) && dm + Doormaster.VentCooldown.GetInt() < GetTimeStamp()) { Main.DoormasterCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.DoormasterCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.DoormasterCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Sapper: - if (Main.SapperCD.TryGetValue(player.PlayerId, out var spp) && spp + Sapper.ShapeshiftCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.SapperCD.TryGetValue(player.PlayerId, out var spp) && spp + Sapper.ShapeshiftCooldown.GetInt() < GetTimeStamp()) { Main.SapperCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.SapperCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.SapperCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Tether: - if (Main.TetherCD.TryGetValue(player.PlayerId, out var th) && th + Tether.VentCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.TetherCD.TryGetValue(player.PlayerId, out var th) && th + Tether.VentCooldown.GetInt() < GetTimeStamp()) { Main.TetherCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.TetherCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.TetherCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.CameraMan: - if (Main.CameraManCD.TryGetValue(player.PlayerId, out var cm) && cm + CameraMan.VentCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.CameraManCD.TryGetValue(player.PlayerId, out var cm) && cm + CameraMan.VentCooldown.GetInt() < GetTimeStamp()) { Main.CameraManCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.CameraManCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.CameraManCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Mayor: - if (Main.MayorCD.TryGetValue(player.PlayerId, out var my) && my + Options.DefaultKillCooldown < Utils.GetTimeStamp()) + if (Main.MayorCD.TryGetValue(player.PlayerId, out var my) && my + Options.DefaultKillCooldown < GetTimeStamp()) { Main.MayorCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.MayorCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.MayorCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Paranoia: - if (Main.ParanoiaCD.TryGetValue(player.PlayerId, out var pn) && pn + Options.ParanoiaVentCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.ParanoiaCD.TryGetValue(player.PlayerId, out var pn) && pn + Options.ParanoiaVentCooldown.GetInt() < GetTimeStamp()) { Main.ParanoiaCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.ParanoiaCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.ParanoiaCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.NiceHacker: - if (Main.HackerCD.TryGetValue(player.PlayerId, out var nh) && nh + NiceHacker.AbilityCD.GetInt() < Utils.GetTimeStamp()) + if (Main.HackerCD.TryGetValue(player.PlayerId, out var nh) && nh + NiceHacker.AbilityCD.GetInt() < GetTimeStamp()) { Main.HackerCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.HackerCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.HackerCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Grenadier: - if (Main.GrenadierCD.TryGetValue(player.PlayerId, out var gd) && gd + Options.GrenadierSkillCooldown.GetInt() + Options.GrenadierSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.GrenadierCD.TryGetValue(player.PlayerId, out var gd) && gd + Options.GrenadierSkillCooldown.GetInt() + Options.GrenadierSkillDuration.GetInt() < GetTimeStamp()) { Main.GrenadierCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.GrenadierCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.GrenadierCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Lighter: - if (Main.LighterCD.TryGetValue(player.PlayerId, out var lt) && lt + Options.LighterSkillCooldown.GetInt() + Options.LighterSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.LighterCD.TryGetValue(player.PlayerId, out var lt) && lt + Options.LighterSkillCooldown.GetInt() + Options.LighterSkillDuration.GetInt() < GetTimeStamp()) { Main.LighterCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.LighterCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.LighterCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.SecurityGuard: - if (Main.SecurityGuardCD.TryGetValue(player.PlayerId, out var sg) && sg + Options.SecurityGuardSkillCooldown.GetInt() + Options.SecurityGuardSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.SecurityGuardCD.TryGetValue(player.PlayerId, out var sg) && sg + Options.SecurityGuardSkillCooldown.GetInt() + Options.SecurityGuardSkillDuration.GetInt() < GetTimeStamp()) { Main.SecurityGuardCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.SecurityGuardCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.SecurityGuardCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.DovesOfNeace: - if (Main.DovesOfNeaceCD.TryGetValue(player.PlayerId, out var don) && don + Options.DovesOfNeaceCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.DovesOfNeaceCD.TryGetValue(player.PlayerId, out var don) && don + Options.DovesOfNeaceCooldown.GetInt() < GetTimeStamp()) { Main.DovesOfNeaceCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.DovesOfNeaceCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.DovesOfNeaceCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Alchemist: - if (Main.AlchemistCD.TryGetValue(player.PlayerId, out var ac) && ac + Alchemist.VentCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.AlchemistCD.TryGetValue(player.PlayerId, out var ac) && ac + Alchemist.VentCooldown.GetInt() < GetTimeStamp()) { Main.AlchemistCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.AlchemistCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.AlchemistCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.TimeMaster: - if (Main.TimeMasterCD.TryGetValue(player.PlayerId, out var tm) && tm + Options.TimeMasterSkillCooldown.GetInt() + Options.TimeMasterSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.TimeMasterCD.TryGetValue(player.PlayerId, out var tm) && tm + Options.TimeMasterSkillCooldown.GetInt() + Options.TimeMasterSkillDuration.GetInt() < GetTimeStamp()) { Main.TimeMasterCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.TimeMasterCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.TimeMasterCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Veteran: - if (Main.VeteranCD.TryGetValue(player.PlayerId, out var vr) && vr + Options.VeteranSkillCooldown.GetInt() + Options.VeteranSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.VeteranCD.TryGetValue(player.PlayerId, out var vr) && vr + Options.VeteranSkillCooldown.GetInt() + Options.VeteranSkillDuration.GetInt() < GetTimeStamp()) { Main.VeteranCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.VeteranCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.VeteranCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Sniper: - if (Main.SniperCD.TryGetValue(player.PlayerId, out var sp) && sp + Options.DefaultShapeshiftCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.SniperCD.TryGetValue(player.PlayerId, out var sp) && sp + Options.DefaultShapeshiftCooldown.GetInt() < GetTimeStamp()) { Main.SniperCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.SniperCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.SniperCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Assassin: - if (Main.AssassinCD.TryGetValue(player.PlayerId, out var ass) && ass + Assassin.AssassinateCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.AssassinCD.TryGetValue(player.PlayerId, out var ass) && ass + Assassin.AssassinateCooldown.GetInt() < GetTimeStamp()) { Main.AssassinCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.AssassinCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.AssassinCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Undertaker: - if (Main.UndertakerCD.TryGetValue(player.PlayerId, out var ut) && ut + Undertaker.AssassinateCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.UndertakerCD.TryGetValue(player.PlayerId, out var ut) && ut + Undertaker.AssassinateCooldown.GetInt() < GetTimeStamp()) { Main.UndertakerCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.UndertakerCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.UndertakerCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Bomber: - if (Main.BomberCD.TryGetValue(player.PlayerId, out var bb) && bb + Options.BombCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.BomberCD.TryGetValue(player.PlayerId, out var bb) && bb + Options.BombCooldown.GetInt() < GetTimeStamp()) { Main.BomberCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.BomberCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.BomberCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Nuker: - if (Main.NukerCD.TryGetValue(player.PlayerId, out var nk) && nk + Options.NukeCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.NukerCD.TryGetValue(player.PlayerId, out var nk) && nk + Options.NukeCooldown.GetInt() < GetTimeStamp()) { Main.NukerCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.NukerCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.NukerCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Escapee: - if (Main.EscapeeCD.TryGetValue(player.PlayerId, out var ec) && ec + Options.EscapeeSSCD.GetInt() < Utils.GetTimeStamp()) + if (Main.EscapeeCD.TryGetValue(player.PlayerId, out var ec) && ec + Options.EscapeeSSCD.GetInt() < GetTimeStamp()) { Main.EscapeeCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.EscapeeCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.EscapeeCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Miner: - if (Main.MinerCD.TryGetValue(player.PlayerId, out var mn) && mn + Options.MinerSSCD.GetInt() < Utils.GetTimeStamp()) + if (Main.MinerCD.TryGetValue(player.PlayerId, out var mn) && mn + Options.MinerSSCD.GetInt() < GetTimeStamp()) { Main.MinerCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.MinerCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.MinerCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Disperser: - if (Main.DisperserCD.TryGetValue(player.PlayerId, out var dp) && dp + Disperser.DisperserShapeshiftCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.DisperserCD.TryGetValue(player.PlayerId, out var dp) && dp + Disperser.DisperserShapeshiftCooldown.GetInt() < GetTimeStamp()) { Main.DisperserCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.DisperserCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.DisperserCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.Twister: - if (Main.TwisterCD.TryGetValue(player.PlayerId, out var ts) && ts + Twister.ShapeshiftCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.TwisterCD.TryGetValue(player.PlayerId, out var ts) && ts + Twister.ShapeshiftCooldown.GetInt() < GetTimeStamp()) { Main.TwisterCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.TwisterCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.TwisterCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; case CustomRoles.QuickShooter: - if (Main.QuickShooterCD.TryGetValue(player.PlayerId, out var qs) && qs + QuickShooter.ShapeshiftCooldown.GetInt() < Utils.GetTimeStamp()) + if (Main.QuickShooterCD.TryGetValue(player.PlayerId, out var qs) && qs + QuickShooter.ShapeshiftCooldown.GetInt() < GetTimeStamp()) { Main.QuickShooterCD.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); } - if (Main.QuickShooterCD.ContainsKey(player.PlayerId)) Utils.NotifyRoles(SpecifySeer: player); + if (Main.QuickShooterCD.ContainsKey(player.PlayerId)) NotifyRoles(SpecifySeer: player); break; } } @@ -2252,7 +2282,7 @@ class FixedUpdatePatch if (targetDistance.Any()) { var min = targetDistance.OrderBy(c => c.Value).FirstOrDefault(); - PlayerControl target = Utils.GetPlayerById(min.Key); + PlayerControl target = GetPlayerById(min.Key); var KillRange = GameOptionsData.KillDistances[Mathf.Clamp(GameOptionsManager.Instance.currentNormalGameOptions.KillDistance, 0, 2)]; if (min.Value <= KillRange && player.CanMove && target.CanMove) Agitater.PassBomb(player, target); @@ -2289,7 +2319,7 @@ class FixedUpdatePatch if (!player.IsAlive() || Pelican.IsEaten(player.PlayerId)) { Main.ArsonistTimer.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: __instance); + NotifyRoles(SpecifySeer: __instance); RPC.ResetCurrentDousingTarget(player.PlayerId); } else @@ -2306,7 +2336,7 @@ class FixedUpdatePatch Main.ArsonistTimer.Remove(player.PlayerId);//塗が完了したのでDictionaryから削除 Main.isDoused[(player.PlayerId, ar_target.PlayerId)] = true;//塗り完了 player.RpcSetDousedPlayer(ar_target, true); - Utils.NotifyRoles(SpecifySeer: player);//名前変更 + NotifyRoles(SpecifySeer: player);//名前変更 RPC.ResetCurrentDousingTarget(player.PlayerId); } else @@ -2321,7 +2351,7 @@ class FixedUpdatePatch else//それ以外は削除 { Main.ArsonistTimer.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); RPC.ResetCurrentDousingTarget(player.PlayerId); Logger.Info($"Canceled: {player.GetNameWithRole().RemoveHtmlTags()}", "Arsonist"); @@ -2337,7 +2367,7 @@ class FixedUpdatePatch if (!player.IsAlive() || Pelican.IsEaten(player.PlayerId)) { Main.RevolutionistTimer.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); RPC.ResetCurrentDrawTarget(player.PlayerId); } else @@ -2354,7 +2384,7 @@ class FixedUpdatePatch Main.RevolutionistTimer.Remove(player.PlayerId);//拉拢完成从字典中删除 Main.isDraw[(player.PlayerId, rv_target.PlayerId)] = true;//完成拉拢 player.RpcSetDrawPlayer(rv_target, true); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); RPC.ResetCurrentDrawTarget(player.PlayerId); if (IRandom.Instance.Next(1, 100) <= Options.RevolutionistKillProbability.GetInt()) { @@ -2376,7 +2406,7 @@ class FixedUpdatePatch else//否则删除 { Main.RevolutionistTimer.Remove(player.PlayerId); - Utils.NotifyRoles(SpecifySeer: __instance); + NotifyRoles(SpecifySeer: __instance); RPC.ResetCurrentDrawTarget(player.PlayerId); Logger.Info($"Canceled: {__instance.GetNameWithRole().RemoveHtmlTags()}", "Revolutionist"); @@ -2390,21 +2420,21 @@ class FixedUpdatePatch { if (Main.RevolutionistLastTime.ContainsKey(player.PlayerId)) { - long nowtime = Utils.GetTimeStamp(); + long nowtime = GetTimeStamp(); if (Main.RevolutionistLastTime[player.PlayerId] != nowtime) Main.RevolutionistLastTime[player.PlayerId] = nowtime; int time = (int)(Main.RevolutionistLastTime[player.PlayerId] - Main.RevolutionistStart[player.PlayerId]); int countdown = Options.RevolutionistVentCountDown.GetInt() - time; Main.RevolutionistCountdown.Clear(); if (countdown <= 0)//倒计时结束 { - Utils.GetDrawPlayerCount(player.PlayerId, out var y); + GetDrawPlayerCount(player.PlayerId, out var y); foreach (var pc in y.Where(x => x != null && x.IsAlive())) { pc.Data.IsDead = true; Main.PlayerStates[pc.PlayerId].deathReason = PlayerState.DeathReason.Sacrifice; pc.Kill(pc); Main.PlayerStates[pc.PlayerId].SetDead(); - Utils.NotifyRoles(SpecifySeer: pc); + NotifyRoles(SpecifySeer: pc); } player.Data.IsDead = true; Main.PlayerStates[player.PlayerId].deathReason = PlayerState.DeathReason.Sacrifice; @@ -2423,7 +2453,7 @@ class FixedUpdatePatch } else //如果不存在字典 { - Main.RevolutionistStart.TryAdd(player.PlayerId, Utils.GetTimeStamp()); + Main.RevolutionistStart.TryAdd(player.PlayerId, GetTimeStamp()); } } #endregion @@ -2437,7 +2467,7 @@ class FixedUpdatePatch switch (player.GetCustomRole()) { case CustomRoles.Veteran when GameStates.IsInTask: - if (Main.VeteranInProtect.TryGetValue(player.PlayerId, out var vtime) && vtime + Options.VeteranSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.VeteranInProtect.TryGetValue(player.PlayerId, out var vtime) && vtime + Options.VeteranSkillDuration.GetInt() < GetTimeStamp()) { Main.VeteranInProtect.Remove(player.PlayerId); player.RpcResetAbilityCooldown(); @@ -2447,7 +2477,7 @@ class FixedUpdatePatch break; case CustomRoles.Express when GameStates.IsInTask: - if (Main.ExpressSpeedUp.TryGetValue(player.PlayerId, out var etime) && etime + Options.ExpressSpeedDur.GetInt() < Utils.GetTimeStamp()) + if (Main.ExpressSpeedUp.TryGetValue(player.PlayerId, out var etime) && etime + Options.ExpressSpeedDur.GetInt() < GetTimeStamp()) { Main.ExpressSpeedUp.Remove(player.PlayerId); Main.AllPlayerSpeed[player.PlayerId] = Main.ExpressSpeedNormal; @@ -2457,25 +2487,25 @@ class FixedUpdatePatch break; case CustomRoles.Grenadier when GameStates.IsInTask: - if (Main.GrenadierBlinding.TryGetValue(player.PlayerId, out var gtime) && gtime + Options.GrenadierSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.GrenadierBlinding.TryGetValue(player.PlayerId, out var gtime) && gtime + Options.GrenadierSkillDuration.GetInt() < GetTimeStamp()) { Main.GrenadierBlinding.Remove(player.PlayerId); player.RpcResetAbilityCooldown(); player.Notify(string.Format(GetString("GrenadierSkillStop"), (int)Main.GrenadierNumOfUsed[player.PlayerId])); - Utils.MarkEveryoneDirtySettingsV3(); + MarkEveryoneDirtySettingsV3(); } - if (Main.MadGrenadierBlinding.TryGetValue(player.PlayerId, out var mgtime) && mgtime + Options.GrenadierSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.MadGrenadierBlinding.TryGetValue(player.PlayerId, out var mgtime) && mgtime + Options.GrenadierSkillDuration.GetInt() < GetTimeStamp()) { Main.MadGrenadierBlinding.Remove(player.PlayerId); player.RpcResetAbilityCooldown(); player.Notify(string.Format(GetString("GrenadierSkillStop"), (int)Main.GrenadierNumOfUsed[player.PlayerId])); - Utils.MarkEveryoneDirtySettingsV3(); + MarkEveryoneDirtySettingsV3(); } break; case CustomRoles.Lighter when GameStates.IsInTask: - if (Main.Lighter.TryGetValue(player.PlayerId, out var ltime) && ltime + Options.LighterSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.Lighter.TryGetValue(player.PlayerId, out var ltime) && ltime + Options.LighterSkillDuration.GetInt() < GetTimeStamp()) { Main.Lighter.Remove(player.PlayerId); player.RpcResetAbilityCooldown(); @@ -2486,7 +2516,7 @@ class FixedUpdatePatch break; case CustomRoles.SecurityGuard when GameStates.IsInTask: - if (Main.BlockSabo.TryGetValue(player.PlayerId, out var stime) && stime + Options.SecurityGuardSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.BlockSabo.TryGetValue(player.PlayerId, out var stime) && stime + Options.SecurityGuardSkillDuration.GetInt() < GetTimeStamp()) { Main.BlockSabo.Remove(player.PlayerId); player.RpcResetAbilityCooldown(); @@ -2497,7 +2527,7 @@ class FixedUpdatePatch case CustomRoles.TimeMaster when GameStates.IsInTask: - if (Main.TimeMasterInProtect.TryGetValue(player.PlayerId, out var ttime) && ttime + Options.TimeMasterSkillDuration.GetInt() < Utils.GetTimeStamp()) + if (Main.TimeMasterInProtect.TryGetValue(player.PlayerId, out var ttime) && ttime + Options.TimeMasterSkillDuration.GetInt() < GetTimeStamp()) { Main.TimeMasterInProtect.Remove(player.PlayerId); player.RpcResetAbilityCooldown(); @@ -2563,7 +2593,7 @@ class FixedUpdatePatch break; } - if (Main.AllKillers.TryGetValue(player.PlayerId, out var ktime) && ktime + Options.WitnessTime.GetInt() < Utils.GetTimeStamp()) Main.AllKillers.Remove(player.PlayerId); + if (Main.AllKillers.TryGetValue(player.PlayerId, out var ktime) && ktime + Options.WitnessTime.GetInt() < GetTimeStamp()) Main.AllKillers.Remove(player.PlayerId); if (GameStates.IsInTask && player.IsAlive() && Options.LadderDeath.GetBool()) FallFromLadder.FixedUpdate(player); if (GameStates.IsInGame) LoversSuicide(); @@ -2593,7 +2623,7 @@ class FixedUpdatePatch if (targetDistance.Any()) { var min = targetDistance.OrderBy(c => c.Value).FirstOrDefault();//一番値が小さい - PlayerControl target = Utils.GetPlayerById(min.Key); + PlayerControl target = GetPlayerById(min.Key); var KillRange = NormalGameOptionsV07.KillDistances[Mathf.Clamp(Main.NormalOptions.KillDistance, 0, 2)]; if (min.Value <= KillRange && player.CanMove && target.CanMove) { @@ -2601,15 +2631,15 @@ class FixedUpdatePatch { var puppeteerId = Main.PuppeteerList[player.PlayerId]; RPC.PlaySoundRPC(puppeteerId, Sounds.KillSound); - target.SetRealKiller(Utils.GetPlayerById(puppeteerId)); + target.SetRealKiller(GetPlayerById(puppeteerId)); player.Kill(target); //Utils.MarkEveryoneDirtySettings(); player.MarkDirtySettings(); target.MarkDirtySettings(); Main.PuppeteerList.Remove(player.PlayerId); //Utils.NotifyRoles(); - Utils.NotifyRoles(SpecifySeer: player); - Utils.NotifyRoles(SpecifySeer: target); + NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: target); } } } @@ -2638,7 +2668,7 @@ class FixedUpdatePatch if (targetDistance.Any()) { var min = targetDistance.OrderBy(c => c.Value).FirstOrDefault();//一番値が小さい - PlayerControl target = Utils.GetPlayerById(min.Key); + PlayerControl target = GetPlayerById(min.Key); var KillRange = NormalGameOptionsV07.KillDistances[Mathf.Clamp(Main.NormalOptions.KillDistance, 0, 2)]; if (min.Value <= KillRange && player.CanMove && target.CanMove) { @@ -2646,15 +2676,15 @@ class FixedUpdatePatch { var puppeteerId = Main.TaglockedList[player.PlayerId]; RPC.PlaySoundRPC(puppeteerId, Sounds.KillSound); - target.SetRealKiller(Utils.GetPlayerById(puppeteerId)); + target.SetRealKiller(GetPlayerById(puppeteerId)); player.Kill(target); //Utils.MarkEveryoneDirtySettings(); player.MarkDirtySettings(); target.MarkDirtySettings(); Main.TaglockedList.Remove(player.PlayerId); //Utils.NotifyRoles(); - Utils.NotifyRoles(SpecifySeer: player); - Utils.NotifyRoles(SpecifySeer: target); + NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: target); } } } @@ -2678,7 +2708,7 @@ class FixedUpdatePatch } if (!Main.DoBlockNameChange && AmongUsClient.Instance.AmHost) - Utils.ApplySuffix(__instance); + ApplySuffix(__instance); } } @@ -2714,7 +2744,7 @@ class FixedUpdatePatch } if (GameStates.IsInGame) { - var RoleTextData = Utils.GetRoleText(PlayerControl.LocalPlayer.PlayerId, __instance.PlayerId); + var RoleTextData = GetRoleText(PlayerControl.LocalPlayer.PlayerId, __instance.PlayerId); //if (Options.CurrentGameMode == CustomGameMode.HideAndSeek) //{ @@ -2726,7 +2756,7 @@ class FixedUpdatePatch if (Options.CurrentGameMode == CustomGameMode.FFA || Options.CurrentGameMode == CustomGameMode.SoloKombat) RoleText.text = string.Empty; - RoleText.enabled = Utils.IsRoleTextEnabled(__instance); + RoleText.enabled = IsRoleTextEnabled(__instance); if (!PlayerControl.LocalPlayer.Data.IsDead && PlayerControl.LocalPlayer.IsRevealedPlayer(__instance) && __instance.Is(CustomRoles.Trickster)) { @@ -2740,7 +2770,7 @@ class FixedUpdatePatch if (!__instance.AmOwner) __instance.cosmetics.nameText.text = __instance?.Data?.PlayerName; } if (Main.VisibleTasksCount) //他プレイヤーでVisibleTasksCountは有効なら - RoleText.text += Utils.GetProgressText(__instance); //ロールの横にタスクなど進行状況表示 + RoleText.text += GetProgressText(__instance); //ロールの横にタスクなど進行状況表示 //変数定義 @@ -2761,11 +2791,11 @@ class FixedUpdatePatch if (target.AmOwner && GameStates.IsInTask) { //targetが自分自身 if (target.Is(CustomRoles.Arsonist) && target.IsDouseDone()) - RealName = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Arsonist), GetString("EnterVentToWin")); + RealName = ColorString(GetRoleColor(CustomRoles.Arsonist), GetString("EnterVentToWin")); else if (target.Is(CustomRoles.Revolutionist) && target.IsDrawDone()) - RealName = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Revolutionist), string.Format(GetString("EnterVentWinCountDown"), Main.RevolutionistCountdown.TryGetValue(seer.PlayerId, out var x) ? x : 10)); + RealName = ColorString(GetRoleColor(CustomRoles.Revolutionist), string.Format(GetString("EnterVentWinCountDown"), Main.RevolutionistCountdown.TryGetValue(seer.PlayerId, out var x) ? x : 10)); if (Pelican.IsEaten(seer.PlayerId)) - RealName = Utils.ColorString(Utils.GetRoleColor(CustomRoles.Pelican), GetString("EatenByPelican")); + RealName = ColorString(GetRoleColor(CustomRoles.Pelican), GetString("EatenByPelican")); if (Options.CurrentGameMode == CustomGameMode.SoloKombat) SoloKombatManager.GetNameNotify(target, ref RealName); @@ -2783,20 +2813,20 @@ class FixedUpdatePatch switch (target.GetCustomRole()) //seerがインポスター { case CustomRoles.Snitch when seer.GetCustomRole().IsImpostor() && target.Is(CustomRoles.Madmate) && target.GetPlayerTaskState().IsTaskFinished: - Mark.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Impostor), "★")); //targetにマーク付与 + Mark.Append(ColorString(GetRoleColor(CustomRoles.Impostor), "★")); //targetにマーク付与 break; case CustomRoles.Marshall when seer.GetCustomRole().IsCrewmate() && target.GetPlayerTaskState().IsTaskFinished: - Mark.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Marshall), "★")); //targetにマーク付与 + Mark.Append(ColorString(GetRoleColor(CustomRoles.Marshall), "★")); //targetにマーク付与 break; case CustomRoles.SuperStar when Options.EveryOneKnowSuperStar.GetBool(): - Mark.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.SuperStar), "★")); + Mark.Append(ColorString(GetRoleColor(CustomRoles.SuperStar), "★")); break; } if (seer.GetCustomRole().IsCrewmate() && seer.Is(CustomRoles.Madmate) && Marshall.MadmateCanFindMarshall) //seerがインポスター { if (target.Is(CustomRoles.Marshall) && target.GetPlayerTaskState().IsTaskFinished) //targetがタスクを終わらせたマッドスニッチ - Mark.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Marshall), "★")); //targetにマーク付与 + Mark.Append(ColorString(GetRoleColor(CustomRoles.Marshall), "★")); //targetにマーク付与 } switch (seer.GetCustomRole()) @@ -2804,37 +2834,37 @@ class FixedUpdatePatch case CustomRoles.Lookout: if (seer.IsAlive() && target.IsAlive()) { - Mark.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Lookout), " " + target.PlayerId.ToString()) + " "); + Mark.Append(ColorString(GetRoleColor(CustomRoles.Lookout), " " + target.PlayerId.ToString()) + " "); } break; case CustomRoles.PlagueBearer when PlagueBearer.IsPlagued(seer.PlayerId, target.PlayerId): - Mark.Append($"●"); + Mark.Append($"●"); // PlagueBearer.SendRPC(seer, target); break; case CustomRoles.Arsonist: if (seer.IsDousedPlayer(target)) { - Mark.Append($"▲"); + Mark.Append($"▲"); } else if ( Main.currentDousingTarget != byte.MaxValue && Main.currentDousingTarget == target.PlayerId ) { - Mark.Append($"△"); + Mark.Append($"△"); } break; case CustomRoles.Revolutionist: if (seer.IsDrawPlayer(target)) { - Mark.Append($"●"); + Mark.Append($"●"); } else if ( Main.currentDrawTarget != byte.MaxValue && Main.currentDrawTarget == target.PlayerId ) { - Mark.Append($"○"); + Mark.Append($"○"); } break; case CustomRoles.Farseer: @@ -2843,13 +2873,13 @@ class FixedUpdatePatch Main.currentDrawTarget == target.PlayerId ) { - Mark.Append($"○"); + Mark.Append($"○"); } break; case CustomRoles.Puppeteer: if (Main.PuppeteerList.ContainsValue(seer.PlayerId) && Main.PuppeteerList.ContainsKey(target.PlayerId)) { - Mark.Append($"◆"); + Mark.Append($"◆"); } break; case CustomRoles.EvilTracker: @@ -2872,10 +2902,10 @@ class FixedUpdatePatch Monitor.FixedUpdate(); if (target.AmOwner) { - if (Monitor.IsAdminWatch) Suffix.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Monitor), GetString("AdminWarning"))); - if (Monitor.IsVitalWatch) Suffix.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Monitor), GetString("VitalsWarning"))); - if (Monitor.IsDoorLogWatch) Suffix.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Monitor), GetString("DoorlogWarning"))); - if (Monitor.IsCameraWatch) Suffix.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.Monitor), GetString("CameraWarning"))); + if (Monitor.IsAdminWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("AdminWarning"))); + if (Monitor.IsVitalWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("VitalsWarning"))); + if (Monitor.IsDoorLogWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("DoorlogWarning"))); + if (Monitor.IsCameraWatch) Suffix.Append(ColorString(GetRoleColor(CustomRoles.Monitor), GetString("CameraWarning"))); } break; } @@ -2890,13 +2920,13 @@ class FixedUpdatePatch if (Medic.IsEnable) { if (seer.PlayerId == target.PlayerId && (Medic.InProtect(seer.PlayerId) || Medic.TempMarkProtected == seer.PlayerId) && (Medic.WhoCanSeeProtect.GetInt() == 0 || Medic.WhoCanSeeProtect.GetInt() == 2)) - Mark.Append($" ●"); + Mark.Append($" ●"); if (seer.Is(CustomRoles.Medic) && (Medic.InProtect(target.PlayerId) || Medic.TempMarkProtected == target.PlayerId) && (Medic.WhoCanSeeProtect.GetInt() == 0 || Medic.WhoCanSeeProtect.GetInt() == 1)) - Mark.Append($" ●"); + Mark.Append($" ●"); if (seer.Data.IsDead && Medic.InProtect(target.PlayerId) && !seer.Is(CustomRoles.Medic)) - Mark.Append($" ●"); + Mark.Append($" ●"); } if (Totocalcio.IsEnable) Mark.Append(Totocalcio.TargetMark(seer, target)); @@ -2911,7 +2941,7 @@ class FixedUpdatePatch } if (BallLightning.IsGhost(target) && BallLightning.IsEnable) - Mark.Append(Utils.ColorString(Utils.GetRoleColor(CustomRoles.BallLightning), "■")); + Mark.Append(ColorString(GetRoleColor(CustomRoles.BallLightning), "■")); //タスクが終わりそうなSnitchがいるとき、インポスター/キル可能なニュートラルに警告が表示される if (Snitch.IsEnable) @@ -2926,11 +2956,11 @@ class FixedUpdatePatch //ハートマークを付ける(会議中MOD視点) if (__instance.Is(CustomRoles.Lovers) && PlayerControl.LocalPlayer.Is(CustomRoles.Lovers)) { - Mark.Append($"♥"); + Mark.Append($"♥"); } else if (__instance.Is(CustomRoles.Lovers) && PlayerControl.LocalPlayer.Data.IsDead) { - Mark.Append($"♥"); + Mark.Append($"♥"); } } //else if (__instance.Is(CustomRoles.Ntr) || PlayerControl.LocalPlayer.Is(CustomRoles.Ntr)) @@ -2984,10 +3014,10 @@ class FixedUpdatePatch RealName = GetString("DevouredName"); // Camouflage - if ((Utils.IsActive(SystemTypes.Comms) && Options.CommsCamouflage.GetBool() && (Main.NormalOptions.MapId != 5 || !Options.CommsCamouflageDisableOnFungle.GetBool())) || Camouflager.IsActive) + if ((IsActive(SystemTypes.Comms) && Options.CommsCamouflage.GetBool() && (Main.NormalOptions.MapId != 5 || !Options.CommsCamouflageDisableOnFungle.GetBool())) || Camouflager.IsActive) RealName = $"{RealName} "; - string DeathReason = seer.Data.IsDead && seer.KnowDeathReason(target) ? $"({Utils.ColorString(Utils.GetRoleColor(CustomRoles.Doctor), Utils.GetVitalText(target.PlayerId))})" : string.Empty; + string DeathReason = seer.Data.IsDead && seer.KnowDeathReason(target) ? $"({ColorString(GetRoleColor(CustomRoles.Doctor), GetVitalText(target.PlayerId))})" : string.Empty; //Mark・Suffixの適用 var currentText = target.cosmetics.nameText.text; @@ -3110,7 +3140,7 @@ class EnterVentPatch { _ = new LateTask(() => { - Utils.SendMessage(GetString("SkillUsedLeft") + (Options.ParanoiaNumOfUseButton.GetInt() - Main.ParaUsedButtonCount[pc.PlayerId]).ToString(), pc.PlayerId); + SendMessage(GetString("SkillUsedLeft") + (Options.ParanoiaNumOfUseButton.GetInt() - Main.ParaUsedButtonCount[pc.PlayerId]).ToString(), pc.PlayerId); }, 4.0f, "Skill Remain Message"); } pc?.MyPhysics?.RpcBootFromVent(__instance.Id); @@ -3122,7 +3152,7 @@ class EnterVentPatch { Main.MarioVentCount.TryAdd(pc.PlayerId, 0); Main.MarioVentCount[pc.PlayerId]++; - Utils.NotifyRoles(SpecifySeer: pc); + NotifyRoles(SpecifySeer: pc); if (pc.AmOwner) { // if (Main.MarioVentCount[pc.PlayerId] % 5 == 0) CustomSoundsManager.Play("MarioCoin"); @@ -3197,12 +3227,12 @@ class EnterVentPatch if (Main.VeteranNumOfUsed[pc.PlayerId] >= 1) { Main.VeteranInProtect.Remove(pc.PlayerId); - Main.VeteranInProtect.Add(pc.PlayerId, Utils.GetTimeStamp(DateTime.Now)); + Main.VeteranInProtect.Add(pc.PlayerId, GetTimeStamp(DateTime.Now)); Main.VeteranNumOfUsed[pc.PlayerId] -= 1; //pc.RpcGuardAndKill(pc); pc.RPCPlayCustomSound("Gunload"); pc.Notify(GetString("VeteranOnGuard"), Options.VeteranSkillDuration.GetFloat()); - Main.VeteranCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); + Main.VeteranCD.TryAdd(pc.PlayerId, GetTimeStamp()); pc.MarkDirtySettings(); } else @@ -3216,21 +3246,21 @@ class EnterVentPatch if (pc.Is(CustomRoles.Madmate)) { Main.MadGrenadierBlinding.Remove(pc.PlayerId); - Main.MadGrenadierBlinding.Add(pc.PlayerId, Utils.GetTimeStamp()); + Main.MadGrenadierBlinding.Add(pc.PlayerId, GetTimeStamp()); Main.AllPlayerControls.Where(x => x.IsModClient()).Where(x => !x.GetCustomRole().IsImpostorTeam() && !x.Is(CustomRoles.Madmate)).Do(x => x.RPCPlayCustomSound("FlashBang")); } else { Main.GrenadierBlinding.Remove(pc.PlayerId); - Main.GrenadierBlinding.Add(pc.PlayerId, Utils.GetTimeStamp()); + Main.GrenadierBlinding.Add(pc.PlayerId, GetTimeStamp()); Main.AllPlayerControls.Where(x => x.IsModClient()).Where(x => x.GetCustomRole().IsImpostor() || x.GetCustomRole().IsNeutral() && Options.GrenadierCanAffectNeutral.GetBool()).Do(x => x.RPCPlayCustomSound("FlashBang")); } //pc.RpcGuardAndKill(pc); pc.RPCPlayCustomSound("FlashBang"); pc.Notify(GetString("GrenadierSkillInUse"), Options.GrenadierSkillDuration.GetFloat()); - Main.GrenadierCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); + Main.GrenadierCD.TryAdd(pc.PlayerId, GetTimeStamp()); Main.GrenadierNumOfUsed[pc.PlayerId] -= 1; - Utils.MarkEveryoneDirtySettingsV3(); + MarkEveryoneDirtySettingsV3(); } else { @@ -3241,9 +3271,9 @@ class EnterVentPatch if (Main.LighterNumOfUsed[pc.PlayerId] >= 1) { Main.Lighter.Remove(pc.PlayerId); - Main.Lighter.Add(pc.PlayerId, Utils.GetTimeStamp()); + Main.Lighter.Add(pc.PlayerId, GetTimeStamp()); pc.Notify(GetString("LighterSkillInUse"), Options.LighterSkillDuration.GetFloat()); - Main.LighterCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); + Main.LighterCD.TryAdd(pc.PlayerId, GetTimeStamp()); Main.LighterNumOfUsed[pc.PlayerId] -= 1; pc.MarkDirtySettings(); } @@ -3256,9 +3286,9 @@ class EnterVentPatch if (Main.SecurityGuardNumOfUsed[pc.PlayerId] >= 1) { Main.BlockSabo.Remove(pc.PlayerId); - Main.BlockSabo.Add(pc.PlayerId, Utils.GetTimeStamp()); + Main.BlockSabo.Add(pc.PlayerId, GetTimeStamp()); pc.Notify(GetString("SecurityGuardSkillInUse"), Options.SecurityGuardSkillDuration.GetFloat()); - Main.SecurityGuardCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); + Main.SecurityGuardCD.TryAdd(pc.PlayerId, GetTimeStamp()); Main.SecurityGuardNumOfUsed[pc.PlayerId] -= 1; } else @@ -3287,11 +3317,11 @@ class EnterVentPatch x.SetKillCooldown(); if (x.Is(CustomRoles.SerialKiller)) { SerialKiller.OnReportDeadBody(); } - x.Notify(Utils.ColorString(Utils.GetRoleColor(CustomRoles.DovesOfNeace), GetString("DovesOfNeaceSkillNotify"))); + x.Notify(ColorString(GetRoleColor(CustomRoles.DovesOfNeace), GetString("DovesOfNeaceSkillNotify"))); }); pc.RPCPlayCustomSound("Dove"); pc.Notify(string.Format(GetString("DovesOfNeaceOnGuard"), Main.DovesOfNeaceNumOfUsed[pc.PlayerId])); - Main.DovesOfNeaceCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); + Main.DovesOfNeaceCD.TryAdd(pc.PlayerId, GetTimeStamp()); } break; case CustomRoles.TimeMaster: @@ -3301,17 +3331,17 @@ class EnterVentPatch Main.TimeMasterNumOfUsed[pc.PlayerId] -= 1; Main.TimeMasterInProtect.Remove(pc.PlayerId); Main.TimeMasterNumOfUsed[pc.PlayerId] -= 1; - Main.TimeMasterInProtect.Add(pc.PlayerId, Utils.GetTimeStamp()); + Main.TimeMasterInProtect.Add(pc.PlayerId, GetTimeStamp()); //if (!pc.IsModClient()) pc.RpcGuardAndKill(pc); pc.Notify(GetString("TimeMasterOnGuard"), Options.TimeMasterSkillDuration.GetFloat()); - Main.TimeMasterCD.TryAdd(pc.PlayerId, Utils.GetTimeStamp()); + Main.TimeMasterCD.TryAdd(pc.PlayerId, GetTimeStamp()); for (int i = 0; i < Main.AllPlayerControls.Count; i++) { PlayerControl player = Main.AllPlayerControls[i]; if (Main.TimeMasterBackTrack.ContainsKey(player.PlayerId)) { var position = Main.TimeMasterBackTrack[player.PlayerId]; - Utils.TP(player.NetTransform, position); + TP(player.NetTransform, position); if (pc != player) player?.MyPhysics?.RpcBootFromVent(player.PlayerId); Main.TimeMasterBackTrack.Remove(player.PlayerId); @@ -3419,7 +3449,7 @@ class CoEnterVentPatch } else if (Options.ArsonistCanIgniteAnytime.GetBool()) { - var douseCount = Utils.GetDousedPlayerCount(__instance.myPlayer.PlayerId).Item1; + var douseCount = GetDousedPlayerCount(__instance.myPlayer.PlayerId).Item1; if (douseCount >= Options.ArsonistMinPlayersToIgnite.GetInt()) // Don't check for max, since the player would not be able to ignite at all if they somehow get more players doused than the max { if (douseCount > Options.ArsonistMaxPlayersToIgnite.GetInt()) Logger.Warn("Arsonist Ignited with more players doused than the maximum amount in the settings", "Arsonist Ignite"); @@ -3458,7 +3488,7 @@ class CoEnterVentPatch if (AmongUsClient.Instance.IsGameStarted && __instance.myPlayer.IsDrawDone())//完成拉拢任务的玩家跳管后 { CustomWinnerHolder.ResetAndSetWinner(CustomWinner.Revolutionist);//革命者胜利 - Utils.GetDrawPlayerCount(__instance.myPlayer.PlayerId, out var x); + GetDrawPlayerCount(__instance.myPlayer.PlayerId, out var x); CustomWinnerHolder.WinnerIds.Add(__instance.myPlayer.PlayerId); for (int i = 0; i < x.Count; i++) { @@ -3479,15 +3509,16 @@ class CoEnterVentPatch //(__instance.myPlayer.Is(CustomRoles.DovesOfNeace) && Main.DovesOfNeaceNumOfUsed.TryGetValue(__instance.myPlayer.PlayerId, out var count5) && count5 < 1) ) { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, (byte)RpcCalls.BootFromVent, SendOption.Reliable, -1); - writer.WritePacked(127); - AmongUsClient.Instance.FinishRpcImmediately(writer); + //MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, (byte)RpcCalls.BootFromVent, SendOption.Reliable, -1); + //writer.WritePacked(127); + //AmongUsClient.Instance.FinishRpcImmediately(writer); _ = new LateTask(() => { - int clientId = __instance.myPlayer.GetClientId(); - MessageWriter writer2 = AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, (byte)RpcCalls.BootFromVent, SendOption.Reliable, clientId); - writer2.Write(id); - AmongUsClient.Instance.FinishRpcImmediately(writer2); + __instance.RpcBootFromVent(id); + //int clientId = __instance.myPlayer.GetClientId(); + //MessageWriter writer2 = AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, (byte)RpcCalls.BootFromVent, SendOption.Reliable, clientId); + //writer2.Write(id); + //AmongUsClient.Instance.FinishRpcImmediately(writer2); }, 0.5f, "Fix DesyncImpostor Stuck"); return false; } @@ -3536,7 +3567,7 @@ class GameDataCompleteTaskPatch { Logger.Info($"TaskComplete:{pc.GetNameWithRole().RemoveHtmlTags()}", "CompleteTask"); Main.PlayerStates[pc.PlayerId].UpdateTask(pc); - Utils.NotifyRoles(SpecifySeer: pc); + NotifyRoles(SpecifySeer: pc); } } [HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.CompleteTask))] @@ -3558,7 +3589,7 @@ class PlayerControlCompleteTaskPatch taskState.CompletedTasksCount++; GameData.Instance.RpcSetTasks(player.PlayerId, Array.Empty()); //タスクを再配布 player.SyncSettings(); - Utils.NotifyRoles(SpecifySeer: player); + NotifyRoles(SpecifySeer: player); return false; } @@ -3574,13 +3605,13 @@ class PlayerControlCompleteTaskPatch { foreach (var impostor in Main.AllAlivePlayerControls.Where(pc => pc.Is(CustomRoleTypes.Impostor))) NameColorManager.Add(impostor.PlayerId, pc.PlayerId, "#ff1919"); - Utils.NotifyRoles(SpecifySeer: pc); + NotifyRoles(SpecifySeer: pc); } if (isTaskFinish && pc.GetCustomRole() is CustomRoles.Doctor or CustomRoles.Sunnyboy or CustomRoles.SpeedBooster) { //ライターもしくはスピードブースターもしくはドクターがいる試合のみタスク終了時にCustomSyncAllSettingsを実行する - Utils.MarkEveryoneDirtySettings(); + MarkEveryoneDirtySettings(); } } } diff --git a/Patches/PlayerJoinAndLeftPatch.cs b/Patches/PlayerJoinAndLeftPatch.cs index e4b5d9406..8c436b23e 100644 --- a/Patches/PlayerJoinAndLeftPatch.cs +++ b/Patches/PlayerJoinAndLeftPatch.cs @@ -218,7 +218,7 @@ class CreatePlayerPatch { if (!AmongUsClient.Instance.AmHost) return; - Logger.Msg($"创建玩家数据:ID{client.Character.PlayerId}: {client.PlayerName}", "CreatePlayer"); + Logger.Msg($"Create player data:ID {client.Character.PlayerId}: {client.PlayerName}", "CreatePlayer"); //规范昵称 var name = client.PlayerName; @@ -238,7 +238,7 @@ class CreatePlayerPatch _ = new LateTask(() => { if (client.Character == null) return; - Logger.Warn($"规范昵称:{client.PlayerName} => {name}", "Name Format"); + Logger.Warn($"Standard nickname:{client.PlayerName} => {name}", "Name Format"); client.Character.RpcSetName(name); }, 1f, "Name Format"); } diff --git a/Patches/RandomSpawnPatch.cs b/Patches/RandomSpawnPatch.cs index 455ef578e..d2aa4c658 100644 --- a/Patches/RandomSpawnPatch.cs +++ b/Patches/RandomSpawnPatch.cs @@ -1,5 +1,4 @@ using HarmonyLib; -using Hazel; using System; using System.Collections.Generic; using System.Linq; @@ -22,7 +21,7 @@ class RandomSpawn var player = Main.AllPlayerControls.FirstOrDefault(p => p.NetTransform == __instance); if (player == null) { - Logger.Warn("プレイヤーがnullです", "RandomSpawn"); + Logger.Warn("Player is null", "RandomSpawn"); return; } if (player.Is(CustomRoles.GM)) return; @@ -43,22 +42,23 @@ class RandomSpawn } public static void TP(CustomNetworkTransform nt, Vector2 location) { - if (AmongUsClient.Instance.AmHost) nt.SnapTo(location); - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(nt.NetId, (byte)RpcCalls.SnapTo, SendOption.None); - NetHelpers.WriteVector2(location, writer); - writer.Write(nt.lastSequenceId); - AmongUsClient.Instance.FinishRpcImmediately(writer); + //if (AmongUsClient.Instance.AmHost) nt.SnapTo(location); + //MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(nt.NetId, (byte)RpcCalls.SnapTo, SendOption.None); + //NetHelpers.WriteVector2(location, writer); + //writer.Write(nt.lastSequenceId); + //AmongUsClient.Instance.FinishRpcImmediately(writer); + Utils.TP(nt, location); } public abstract class SpawnMap { public virtual void RandomTeleport(PlayerControl player) { - var location = GetLocation(); - Logger.Info($"{player.Data.PlayerName}:{location}", "RandomSpawn"); - TP(player.NetTransform, location); + var spawn = GetLocation(); + Logger.Info($"{player.Data.PlayerName} => {spawn.Key} ({spawn.Value})", "RandomSpawn"); + TP(player.NetTransform, spawn.Value); } - public abstract Vector2 GetLocation(); + public abstract KeyValuePair GetLocation(); } public class SkeldSpawnMap : SpawnMap @@ -80,9 +80,9 @@ class RandomSpawn ["Reactor"] = new(-20.5f, -5.5f), ["MedBay"] = new(-9.0f, -4.0f) }; - public override Vector2 GetLocation() + public override KeyValuePair GetLocation() { - return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault().Value; + return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } public class MiraHQSpawnMap : SpawnMap @@ -104,9 +104,9 @@ class RandomSpawn ["Office"] = new(15.0f, 19.0f), ["Greenhouse"] = new(17.8f, 23.0f) }; - public override Vector2 GetLocation() + public override KeyValuePair GetLocation() { - return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault().Value; + return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } public class PolusSpawnMap : SpawnMap @@ -129,9 +129,9 @@ class RandomSpawn ["Toilet"] = new(34.0f, -10.0f), ["SpecimenRoom"] = new(36.5f, -22.0f) }; - public override Vector2 GetLocation() + public override KeyValuePair GetLocation() { - return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault().Value; + return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } public class AirshipSpawnMap : SpawnMap @@ -158,11 +158,11 @@ class RandomSpawn ["Toilet"] = new(30.9f, 6.8f), ["Showers"] = new(21.2f, -0.8f) }; - public override Vector2 GetLocation() + public override KeyValuePair GetLocation() { return Options.AirshipAdditionalSpawn.GetBool() - ? positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault().Value - : positions.ToArray()[0..6].OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault().Value; + ? positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault() + : positions.ToArray()[0..6].OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } public class FungleSpawnMap : SpawnMap @@ -188,9 +188,9 @@ class RandomSpawn ["UpperEngine"] = new Vector2(22.4f, 3.4f), ["Communications"] = new Vector2(22.2f, 13.7f) }; - public override Vector2 GetLocation() + public override KeyValuePair GetLocation() { - return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault().Value; + return positions.ToArray().OrderBy(_ => Guid.NewGuid()).Take(1).FirstOrDefault(); } } } \ No newline at end of file diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs index ef94066a8..ed29b663c 100644 --- a/Patches/ShipStatusPatch.cs +++ b/Patches/ShipStatusPatch.cs @@ -220,7 +220,7 @@ class StartPatch public static void Postfix() { Logger.CurrentMethod(); - Logger.Info("-----------游戏开始-----------", "Phase"); + Logger.Info("-----------Game start-----------", "Phase"); Utils.CountAlivePlayers(true); diff --git a/Patches/TaskAssignPatch.cs b/Patches/TaskAssignPatch.cs index 5723af9e8..2a3590324 100644 --- a/Patches/TaskAssignPatch.cs +++ b/Patches/TaskAssignPatch.cs @@ -77,7 +77,7 @@ class AddTasksFromListPatch for (int i = 0; i < disabledTasks.Count; i++) { NormalPlayerTask task = disabledTasks[i]; - Logger.Msg("削除: " + task.TaskType.ToString(), "AddTask"); + Logger.Msg("Deleted assigned task: " + task.TaskType.ToString(), "AddTask"); unusedTasks.Remove(task); } } diff --git a/Patches/onGameStartedPatch.cs b/Patches/onGameStartedPatch.cs index a204001ad..4f03a3505 100644 --- a/Patches/onGameStartedPatch.cs +++ b/Patches/onGameStartedPatch.cs @@ -420,9 +420,9 @@ internal class SelectRolesPatch var kp = RoleResult.FirstOrDefault(x => x.Key.PlayerId == sd.Item1.PlayerId); newList.Add((sd.Item1, kp.Value.GetRoleTypes())); if (sd.Item2 == kp.Value.GetRoleTypes()) - Logger.Warn($"注册原版职业 => {sd.Item1.GetRealName()}: {sd.Item2}", "Override Role Select"); + Logger.Warn($"Register original role type => {sd.Item1.GetRealName()}: {sd.Item2}", "Override Role Select"); else - Logger.Warn($"覆盖原版职业 => {sd.Item1.GetRealName()}: {sd.Item2} => {kp.Value.GetRoleTypes()}", "Override Role Select"); + Logger.Warn($"Register original role type => {sd.Item1.GetRealName()}: {sd.Item2} => {kp.Value.GetRoleTypes()}", "Override Role Select"); } if (Options.EnableGM.GetBool()) newList.Add((PlayerControl.LocalPlayer, RoleTypes.Crewmate)); RpcSetRoleReplacer.StoragedData = newList; @@ -1068,7 +1068,7 @@ internal class SelectRolesPatch player.SetRole(othersRole); player.Data.IsDead = true; - Logger.Info($"注册模组职业:{player?.Data?.PlayerName} => {role}", "AssignRoles"); + Logger.Info($"Register Modded Role:{player?.Data?.PlayerName} => {role}", "AssignRoles"); } public static void MakeDesyncSender(Dictionary senders, Dictionary<(byte, byte), RoleTypes> rolesMap) { @@ -1093,7 +1093,7 @@ internal class SelectRolesPatch SetColorPatch.IsAntiGlitchDisabled = true; Main.PlayerStates[player.PlayerId].SetMainRole(role); - Logger.Info($"注册模组职业:{player?.Data?.PlayerName} => {role}", "AssignRoles"); + Logger.Info($"Register Modded Role:{player?.Data?.PlayerName} => {role}", "AssignRoles"); SetColorPatch.IsAntiGlitchDisabled = false; } diff --git a/Resources/Config/EACList.txt b/Resources/Config/EACList.txt index f6ae39c9a..386ed101b 100644 --- a/Resources/Config/EACList.txt +++ b/Resources/Config/EACList.txt @@ -60,6 +60,8 @@ storedusty#6125,o O farcorn#5146,Acfun tilesteep#2740,Engineer imagetense#5619,Chinese//Non aum hacker +gabledebb#2717.部屋潰しガチ勢SEX +coopfunny#1119,Terklom ## Griefer setmolar#4374,藏族顶针 @@ -68,9 +70,13 @@ roomybump#8560,中国国民党 whipsame#5558,齐心 习母 epicdoer#2966,毛泽车 ternaryjog#6069,习皇帝万岁 +bigtunnel#1506,카제하야가꿈 //Discrimination against Chinese ## 冒充开发者 polkaoval#0453,自作Modな橋本環奈 ## Other -tenthrope#3476,Dronecool \ No newline at end of file +tenthrope#3476,Dronecool +## teaming and harassing hosts in multiple lobbies +broadbarn#7413,niah +tidytrice#2024,Alisa?(either this or above one) \ No newline at end of file diff --git a/Resources/String.csv b/Resources/String.csv index 3f7c8e2fd..53d6ce967 100644 --- a/Resources/String.csv +++ b/Resources/String.csv @@ -788,7 +788,7 @@ "TimeManagerInfoLong","(船员阵营):\n时间操控者做的任务越多,会议时间就会越长,当时间操控者死亡则会议时间恢复正常。当时间操控者成为叛徒时则技能变为减少会议时长而不是增加会议时长。","(Crewmates):\nThe more tasks the Time Manager does, the longer the meeting time will be. When the Time Manager dies, the meeting time will return to normal. When the Time Manager becomes a Madmate, the skill changes to reducing the meeting time instead of increasing it.","(Член Экипажа):\nМастер Времени может увеличить время встречи, увеличивается время по мере выполнения заданий. Но когда он умрет, время встречи будет сброшено по умолчанию.","(船員陣營):\n時間大師做的任務越多,那麼會議時間就越長,如果時間大師死亡,那麼會議時間恢復。如果時間大師成為叛徒,那麼會議時間將會減少而不是增加。","(船员阵营):\n时间操控者做的任务越多,会议时间就会越长,当时间操控者死亡则会议时间恢复正常。当时间操控者成为叛徒时则技能变为减少会议时长而不是增加会议时长。" "VeteranInfoLong","(船员阵营):\n老兵可以通过使用通风管道进入戒备状态,如果戒备状态下有玩家尝试击杀老兵,则老兵反杀凶手。老兵进入以及退出戒备状态时会看到自己身上有护盾破碎作为提示。","(Crewmates):\nVeteran can enter the alert state by venting/petting. If a player tries to kill the veteran in the alert state, the veteran will kill the murderer instead. Veteran will see a shield-animation on their body and a text displayed above their head as a reminder when they enter and exit the alert state.","(Член Экипажа):\nВетеран может перейти в состояние боевой готовности, используя вентиляцию. Если игрок попытается убить Ветерана в состоянии боевой готовности, то Ветеран тут же убьет убийцу. Когда Ветеран входят в состояние боевой готовности и выходят из него, он увидит сломанный щит ангела на своем теле в качестве напоминания.","(船員陣營):\n老兵可以通過使用通風管來進入戒備狀態,在戒備狀態下,如果有人嘗試殺死老兵,那麼老兵將反殺嘗試殺死他的玩家。老兵進入或退出戒備狀態時身上會有盾牌破碎的效果作為提示。\n請注意: 如果老兵在戒備狀態下被鵜鶘活吞,那麼老兵將不會發動技能。","(船员阵营):\n老兵可以通过使用通风管道进入戒备状态,如果戒备状态下有玩家尝试击杀老兵,则老兵反杀凶手。老兵进入以及退出戒备状态时会看到自己身上有护盾破碎作为提示。" "CopyCatInfoLong","(船员阵营):\n模仿者可以使用击杀按钮复制别人的职业\n如果目标是非船员或者流氓的话,则可能会杀死目标\n同时,若复制了太多非船员角色的话,则会自杀","(Crewmate):\nAs the Copycat, you can use your kill button to copy target's role.\n\nYou can only copy some crewmate roles.\nAccording to host settings, if you try to copy non-crew or a Rascal's role you may kill them instead.\n\nAdditionally, You do not have access to guessing and you suicide after miscopying certain number of times that is set by the host.","","","" -"BodyguardInfoLong","(船员阵营):\n在保镖附近如果有玩家将被击杀,则保镖会阻止这次击杀并与凶手同归于尽。保镖的技能会作用在任何阵营的玩家上。当保镖成为叛徒且凶手不是内鬼的时候,保镖不会发动技能。","(Crewmates):\nIf a player is about to be killed near the Bodyguard, the Bodyguard will prevent the kill and die with the murderer. The Bodyguard's skills will affect players of any team. When the Bodyguard becomes a Madmate and the murderer is not an Impostor, the Bodyguard will not activate the skill.","(Член Экипажа):\nЕсли убийца попытается убить игрока рядом с Телохранителем, то Тело-Хранитель предотвратит убийство и умрет вместе с убийцей. Пожалуйста, обратите внимание: Навыки Телохранителем будут работать на игроках любой команды.","(船員陣營):\n如果在保鑣附近有玩家被嘗試殺死,則保鑣將會阻止這次的殺人並和兇手同歸於盡,當保鑣成為叛徒並凶手不是偽裝者陣營的玩家時,則保鑣不會發動技能。\n請注意: 如果在保鑣附近有玩家被鵜鶘活吞,則保鑣不會發動技能。","(船员阵营):\n在保镖附近如果有玩家将被击杀,则保镖会阻止这次击杀并与凶手同归于尽。保镖的技能会作用在任何阵营的玩家上。当保镖成为叛徒且凶手不是内鬼的时候,保镖不会发动技能。" +"BodyguardInfoLong","(船员阵营):\n在保镖附近如果有玩家将被击杀,则保镖会阻止这次击杀并与凶手同归于尽。保镖的技能会作用在任何阵营的玩家上。当保镖成为叛徒且凶手不是内鬼的时候,保镖不会发动技能。","(Crewmates):\nIf a player is about to be killed near the Bodyguard, the Bodyguard will prevent the kill and die with the murderer. The Bodyguard's skills will affect players of any team. When the Bodyguard becomes a Madmate and the murderer is an Impostor, the Bodyguard will not activate the skill.","(Член Экипажа):\nЕсли убийца попытается убить игрока рядом с Телохранителем, то Тело-Хранитель предотвратит убийство и умрет вместе с убийцей. Пожалуйста, обратите внимание: Навыки Телохранителем будут работать на игроках любой команды.","(船員陣營):\n如果在保鑣附近有玩家被嘗試殺死,則保鑣將會阻止這次的殺人並和兇手同歸於盡,當保鑣成為叛徒並凶手不是偽裝者陣營的玩家時,則保鑣不會發動技能。\n請注意: 如果在保鑣附近有玩家被鵜鶘活吞,則保鑣不會發動技能。","(船员阵营):\n在保镖附近如果有玩家将被击杀,则保镖会阻止这次击杀并与凶手同归于尽。保镖的技能会作用在任何阵营的玩家上。当保镖成为叛徒且凶手不是内鬼的时候,保镖不会发动技能。" "CounterfeiterInfoLong","(船员阵营):\n赝品商可以通过击杀键将赝品卖给其他玩家,如贩卖成功赝品商将会看到自己身上出现护盾破碎动画作为提示。赝品将在下一次会议结束后生效,若无击杀能力的玩家持有赝品会立刻走火自杀,若有击杀能力的玩家持有赝品将在他下次尝试击杀时走火自杀。","(Crewmates):\nThe Deceiver can sell the counterfeit to other players through the kill button. If the counterfeit is sold successfully, the Deceiver will see a shield animation on their body as a reminder. The counterfeit will take effect after the end of the next meeting. If the player with no kill ability holds the counterfeit, he will kill himself immediately. If the player with the kill ability has the counterfeit, he will suicide when he tries to kill someone next time.","(Член Экипажа):\nОбманщик может прередать Обманку другим игрокам с помощью кнопки ''Убить''. Если обманка пройдет успешно, Обманщик увидит анимацию сломанного щита на своем теле в качестве напоминания. Обман вступит в силу после окончания следующей встречи. Если игрок с обманкой будет без способности убивать, он немедленно совершит самоубийство. Если игрок с обманкой будет со способностью убивать игроков, он совершит самоубийство при следующей попытке убить игрока.","(船員陣營):\n贗品商可以通過殺人鍵將贗品賣給其他玩家,若販賣成功那麼贗品商身上將會有盾牌破碎的效果作為提示,贗品將在會議結束後生效,如果未持有殺人能力的玩家持有贗品,那麼將立刻走火自殺,反之,如果持有殺人能力的玩家也持有贗品,那麼他將在下次殺死某個人時走火自殺。","(船员阵营):\n赝品商可以通过击杀键将赝品卖给其他玩家,如贩卖成功赝品商将会看到自己身上出现护盾破碎动画作为提示。赝品将在下一次会议结束后生效,若无击杀能力的玩家持有赝品会立刻走火自杀,若有击杀能力的玩家持有赝品将在他下次尝试击杀时走火自杀。" "GrenadierInfoLong","(船员阵营):\n掷雷兵可以通过使用通风管道使用闪光弹,闪光弹会导致内鬼失去大部分视野(根据房主设置闪光弹可能影响到中立阵营玩家)。闪光弹生效以及失效时掷雷兵会看到自己身上有护盾破碎作为提示。当掷雷兵成为叛徒时闪光弹只对船员生效。","(Crewmates):\nThe Grenadier can use vent/pet to use the flashbang, which will cause the Impostor to lose most of the vision (depending on the host's settings, the flashbang may affect neutrals). When the flashbang takes effect and fails, the Grenadier will see the shield-animation on their body as a reminder. Flashbangs only work on the Crewmate when the Grenadier becomes a Madmate.","(Член Экипажа):\nГренадёр может использовать светошумовую бомбу, используя вентиляцию. Светошумовая бомба приведёт к тому, что Предатели потеряют большую часть поля зрения (поле зрение зависит от настроек Хоста, так же светошумовые бомбы могут повлиять на нейтралов). Когда светошумовая бомба сработает и не сработает, гренадер увидит, что их щиты разбиты в качестве напоминания","(船員陣營):\n擲彈兵可以通過使用通風管來使用閃光彈,閃光彈會導致偽裝者陣營的玩家失去大部分的視野(根據房主設定,效果可能影響到中立玩家),閃光彈生效或失效時擲彈兵會看到自己身上有盾牌破碎的效果作為提示。當擲彈兵成為叛徒時,閃光彈將只對船員生效。","(船员阵营):\n掷雷兵可以通过使用通风管道使用闪光弹,闪光弹会导致内鬼失去大部分视野(根据房主设置闪光弹可能影响到中立阵营玩家)。闪光弹生效以及失效时掷雷兵会看到自己身上有护盾破碎作为提示。当掷雷兵成为叛徒时闪光弹只对船员生效。" "LighterInfoLong","","(Crewmate):\nAs the Lighter, you can vent/pet to increase your vision temporarily.\nYou have increased vision both when lights are not out and when lights are out.\nUse this power to catch sneaky killers!","","","" @@ -1393,6 +1393,7 @@ "TransporterTeleportMax","传送次数上限","Max number of teleports","Максимальное колличество телепортов","傳送次數上限","传送次数上限" "TriggerKill","击杀","Kill","Убийство","殺死","击杀" "UsePets","","Use Pet button instead of Vent / Shapeshift","","","" +"UseVoteCancelling","","Use Vote Cancelling Method instead of Commands","","","" "AbilityOnCooldown","","Ability on cooldown!","","","" "KillCooldownOnStrangle","","Kill Cooldown after Strangling","","","" "CDPT","","CD: {0}s","","","" @@ -2069,7 +2070,7 @@ "ERR-000-910-1","测试错误Lv1","Test Error Lv.1","Ошибка теста - Lv1","測試錯誤Lv1","测试错误Lv1" "ERR-000-920-2","测试错误Lv2","Test Error Lv.2","Ошибка теста - Lv2","測試錯誤Lv2","测试错误Lv2" "ERR-000-930-3","测试错误Lv3","Test Error Lv.3","Ошибка теста - Lv3","測試錯誤Lv3","测试错误Lv3" -"ERR-000-804-1","测试错误未知","TownOfHostEdited does not support the Vanilla HnS, so unloaded.","Мод не поддерживает обычные Прятки. Мод был отключён","測試錯誤未知","测试错误未知" +"ERR-000-804-1","测试错误未知","TOHE+ does not support the Vanilla HnS, so unloaded.","Мод не поддерживает обычные Прятки. Мод был отключён","測試錯誤未知","测试错误未知" "#### 001 Main," "ERR-001-000-3","在主目录出现重复密钥","Main dictionary has duplicated keys.","Дублирование ключей происходит в основном словаре.","在矚目路出現重複密鑰","在主目录出现重复密钥" @@ -2819,13 +2820,13 @@ "## Doormaster" "Doormaster","","Door Master","","","" -"DoormasterInfo","","Vent to Open All Doors","","","" +"DoormasterInfo","","Open All Doors Anytime","","","" "DoormasterInfoLong","","(Crewmates):\nAs the Door Master, you can vent/pet to open all closed doors.\n\nDue to technical difficulties, this may not work on some maps.","","","" "## Ricochet" "Ricochet","","Ricochet","","","" "RicochetInfo","","Protect yourself from someone specific","","","" -"RicochetInfoLong","","(Crewmates):\nAs the Ricochat, you may vote someone in a meeting to make them your target.\nIn the next round, your target will not be able to kill you.","","","" +"RicochetInfoLong","","(Crewmates):\nAs the Ricochet, you may vote someone in a meeting to make them your target.\nIn the next round, your target will not be able to kill you.","","","" "## Spy" "Spy","","Spy","","","" @@ -2883,7 +2884,7 @@ "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!","","","" +"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 with {0} guesses left!","","","" "## Bandit" "Bandit","","Bandit","","","" diff --git a/Roles/Crewmate/Aid.cs b/Roles/Crewmate/Aid.cs index 76d75f513..5b0a46c7a 100644 --- a/Roles/Crewmate/Aid.cs +++ b/Roles/Crewmate/Aid.cs @@ -26,7 +26,7 @@ namespace TOHE.Roles.Crewmate .SetValueFormat(OptionFormat.Seconds); AidDur = FloatOptionItem.Create(Id + 11, "AidDur", new(0f, 70f, 1f), 10f, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) .SetValueFormat(OptionFormat.Seconds); - UseLimitOpt = IntegerOptionItem.Create(Id + 12, "AbilityUseLimit", new(1, 20, 1), 1, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) + UseLimitOpt = IntegerOptionItem.Create(Id + 12, "AbilityUseLimit", new(1, 20, 1), 5, TabGroup.CrewmateRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Aid]) .SetValueFormat(OptionFormat.Times); } public static void Init() diff --git a/Roles/Crewmate/Alchemist.cs b/Roles/Crewmate/Alchemist.cs index f69fb3ca9..923f3a9b3 100644 --- a/Roles/Crewmate/Alchemist.cs +++ b/Roles/Crewmate/Alchemist.cs @@ -66,9 +66,31 @@ namespace TOHE.Roles.Crewmate { playerIdList.Add(playerId); PlayerName = Utils.GetPlayerById(playerId).GetRealName(); + _ = new LateTask(() => { SendRPCData(IsProtected, PotionID, PlayerName, VisionPotionActive, FixNextSabo); }, 10f, "Alchemist RPCs"); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPCData(bool isProtected, byte potionId, string playerName, bool visionPotionActive, bool fixNextSabo) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetAlchemistPotion, SendOption.Reliable, -1); + writer.Write(isProtected); + writer.Write(potionId); + writer.Write(playerName); + writer.Write(visionPotionActive); + writer.Write(fixNextSabo); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPCData(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + IsProtected = reader.ReadBoolean(); + PotionID = reader.ReadByte(); + PlayerName = reader.ReadString(); + VisionPotionActive = reader.ReadBoolean(); + FixNextSabo = reader.ReadBoolean(); + } + public static void OnTaskComplete(PlayerControl pc) { PotionID = (byte)HashRandom.Next(1, 8); @@ -178,6 +200,8 @@ namespace TOHE.Roles.Crewmate Main.AlchemistCD.TryAdd(player.PlayerId, Utils.GetTimeStamp()); + SendRPCData(IsProtected, PotionID, PlayerName, VisionPotionActive, FixNextSabo); + PotionID = 10; } private static long lastFixedTime; diff --git a/Roles/Crewmate/Bloodhound.cs b/Roles/Crewmate/Bloodhound.cs index 6a507c874..e48d770b1 100644 --- a/Roles/Crewmate/Bloodhound.cs +++ b/Roles/Crewmate/Bloodhound.cs @@ -74,6 +74,25 @@ LocateArrow.RemoveAllTarget(playerId); } + public static void SendRPCPlus(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.BloodhoundIncreaseAbilityUseByOne, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + + public static void ReceiveRPCPlus(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) UseLimit[playerId]--; + else UseLimit[playerId]++; + } + public static void Clear() { for (int i = 0; i < playerIdList.Count; i++) @@ -126,6 +145,7 @@ pc.Notify(GetString("BloodhoundTrackRecorded")); UseLimit[pc.PlayerId] -= 1; + SendRPCPlus(pc.PlayerId, true); if (LeaveDeadBodyUnreportable.GetBool()) { diff --git a/Roles/Crewmate/CameraMan.cs b/Roles/Crewmate/CameraMan.cs index c316d7f13..0372aa329 100644 --- a/Roles/Crewmate/CameraMan.cs +++ b/Roles/Crewmate/CameraMan.cs @@ -1,5 +1,6 @@ namespace TOHE.Roles.Crewmate { + using Hazel; using System; using System.Collections.Generic; using System.Linq; @@ -40,6 +41,23 @@ namespace TOHE.Roles.Crewmate UseLimit.Add(playerId, UseLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetCameraManLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) UseLimit[playerId]--; + else UseLimit[playerId]++; + } public static void OnEnterVent(PlayerControl pc) { if (pc == null) return; @@ -48,6 +66,7 @@ namespace TOHE.Roles.Crewmate if (UseLimit[pc.PlayerId] >= 1) { UseLimit[pc.PlayerId] -= 1; + SendRPC(pc.PlayerId, true); Main.CameraManCD.TryAdd(pc.PlayerId, GetTimeStamp()); Vector2 pos; diff --git a/Roles/Crewmate/Chameleon.cs b/Roles/Crewmate/Chameleon.cs index a4e9eddc7..d532ab71d 100644 --- a/Roles/Crewmate/Chameleon.cs +++ b/Roles/Crewmate/Chameleon.cs @@ -67,6 +67,23 @@ public static class Chameleon if (invis > 0) InvisTime.Add(PlayerControl.LocalPlayer.PlayerId, invis); if (last > 0) lastTime.Add(PlayerControl.LocalPlayer.PlayerId, last); } + public static void SendRPCPlus(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetChameleonLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPCPlus(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) UseLimit[playerId]--; + else UseLimit[playerId]++; + } public static bool CanGoInvis(byte id) => GameStates.IsInTask && !InvisTime.ContainsKey(id) && !lastTime.ContainsKey(id); public static bool IsInvis(byte id) => InvisTime.ContainsKey(id); @@ -147,6 +164,7 @@ public static class Chameleon NameNotifyManager.Notify(pc, GetString("ChameleonInvisState"), ChameleonDuration.GetFloat()); UseLimit[pc.PlayerId] -= 1; + SendRPCPlus(pc.PlayerId, true); } else { diff --git a/Roles/Crewmate/Divinator.cs b/Roles/Crewmate/Divinator.cs index b07269bd8..f144cfa1b 100644 --- a/Roles/Crewmate/Divinator.cs +++ b/Roles/Crewmate/Divinator.cs @@ -1,3 +1,4 @@ +using Hazel; using System.Collections.Generic; using System.Linq; using static TOHE.Options; @@ -42,6 +43,23 @@ public static class Divinator CheckLimit.TryAdd(playerId, CheckLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDivinatorLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) CheckLimit[playerId]--; + else CheckLimit[playerId]++; + } public static void OnVote(PlayerControl player, PlayerControl target) { if (player == null || target == null) return; @@ -55,6 +73,7 @@ public static class Divinator } CheckLimit[player.PlayerId] -= 1; + SendRPC(player.PlayerId, true); if (player.PlayerId == target.PlayerId) { diff --git a/Roles/Crewmate/Doormaster.cs b/Roles/Crewmate/Doormaster.cs index 010157940..998e6d93c 100644 --- a/Roles/Crewmate/Doormaster.cs +++ b/Roles/Crewmate/Doormaster.cs @@ -1,5 +1,6 @@ namespace TOHE.Roles.Crewmate { + using Hazel; using System; using System.Collections.Generic; using System.Linq; @@ -41,6 +42,23 @@ namespace TOHE.Roles.Crewmate UseLimit.Add(playerId, UseLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetDoormasterLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) UseLimit[playerId]--; + else UseLimit[playerId]++; + } public static void OnEnterVent(PlayerControl pc) { if (pc == null) return; @@ -49,6 +67,7 @@ namespace TOHE.Roles.Crewmate if (UseLimit[pc.PlayerId] >= 1) { UseLimit[pc.PlayerId] -= 1; + SendRPC(pc.PlayerId, true); DoorsReset.OpenAllDoors(); Main.DoormasterCD.TryAdd(pc.PlayerId, GetTimeStamp()); } diff --git a/Roles/Crewmate/Enigma.cs b/Roles/Crewmate/Enigma.cs index 123a8c5a4..d4aef6ef7 100644 --- a/Roles/Crewmate/Enigma.cs +++ b/Roles/Crewmate/Enigma.cs @@ -94,8 +94,9 @@ namespace TOHE.Roles.Crewmate string msg; var rd = IRandom.Instance; - foreach (var playerId in playerIdList) + for (int i = 0; i < playerIdList.Count; i++) { + byte playerId = playerIdList[i]; if (!EnigmaGetCluesWithoutReporting.GetBool() && playerId != player.PlayerId) continue; var enigmaPlayer = Utils.GetPlayerById(playerId); @@ -161,7 +162,7 @@ namespace TOHE.Roles.Crewmate if (killerOutfit.HatId == "hat_EmptyHat") return GetString("EnigmaClueHat2"); - switch (this.ClueStage) + switch (ClueStage) { case 1: case 2: @@ -185,7 +186,7 @@ namespace TOHE.Roles.Crewmate if (killerOutfit.VisorId == "visor_EmptyVisor") return GetString("EnigmaClueVisor2"); - switch (this.ClueStage) + switch (ClueStage) { case 1: case 2: @@ -209,7 +210,7 @@ namespace TOHE.Roles.Crewmate if (killerOutfit.SkinId == "skin_EmptySkin") return GetString("EnigmaClueSkin2"); - switch (this.ClueStage) + switch (ClueStage) { case 1: case 2: @@ -233,7 +234,7 @@ namespace TOHE.Roles.Crewmate if (killerOutfit.PetId == "pet_EmptyPet") return GetString("EnigmaCluePet2"); - switch (this.ClueStage) + switch (ClueStage) { case 1: case 2: @@ -258,7 +259,7 @@ namespace TOHE.Roles.Crewmate string killerName = killer.GetRealName(); string letter = killerName[rd.Next(0, killerName.Length - 1)].ToString().ToLower(); - switch (this.ClueStage) + switch (ClueStage) { case 1: return GetStage1Clue(killer, letter); @@ -320,7 +321,7 @@ namespace TOHE.Roles.Crewmate { int length = killer.GetRealName().Length; - switch (this.ClueStage) + switch (ClueStage) { case 1: return GetStage1Clue(length); @@ -371,7 +372,7 @@ namespace TOHE.Roles.Crewmate { var killerOutfit = Camouflage.PlayerSkins[killer.PlayerId]; - switch (this.ClueStage) + switch (ClueStage) { case 1: case 2: @@ -429,7 +430,7 @@ namespace TOHE.Roles.Crewmate public override string GetMessage(PlayerControl killer, bool showStageClue) { CustomRoles role = killer.GetCustomRole(); - switch (this.ClueStage) + switch (ClueStage) { case 1: if (role.IsImpostor()) return GetString("EnigmaClueRole1"); @@ -455,7 +456,7 @@ namespace TOHE.Roles.Crewmate { int level = (int)killer.Data.PlayerLevel; - switch (this.ClueStage) + switch (ClueStage) { case 1: return GetStage1Clue(level); diff --git a/Roles/Crewmate/Judge.cs b/Roles/Crewmate/Judge.cs index 96994d142..640a9fa3d 100644 --- a/Roles/Crewmate/Judge.cs +++ b/Roles/Crewmate/Judge.cs @@ -58,11 +58,11 @@ public static class Judge public static bool IsEnable => playerIdList.Any(); public static void OnReportDeadBody() { - TrialLimit.Clear(); - for (int i = 0; i < playerIdList.Count; i++) + List list = TrialLimit.Keys.ToList(); + for (int i = 0; i < list.Count; i++) { - byte pc = playerIdList[i]; - TrialLimit.Add(pc, TrialLimitPerMeeting.GetInt()); + byte pid = list[i]; + TrialLimit[pid] = TrialLimitPerMeeting.GetInt(); } } public static bool TrialMsg(PlayerControl pc, string msg, bool isUI = false) diff --git a/Roles/Crewmate/Mediumshiper.cs b/Roles/Crewmate/Mediumshiper.cs index daef7e555..4d0d229b9 100644 --- a/Roles/Crewmate/Mediumshiper.cs +++ b/Roles/Crewmate/Mediumshiper.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; using static TOHE.Translator; @@ -38,6 +39,23 @@ public static class Mediumshiper ContactLimit.Add(playerId, ContactLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetMediumshiperLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) ContactLimit[playerId]--; + else ContactLimit[playerId]++; + } public static void OnReportDeadBody(GameData.PlayerInfo target) { ContactPlayer = new(); @@ -46,8 +64,9 @@ public static class Mediumshiper { if (ContactLimit[pc.PlayerId] < 1) continue; ContactLimit[pc.PlayerId] -= 1; + SendRPC(pc.PlayerId, true); ContactPlayer.TryAdd(target.PlayerId, pc.PlayerId); - Logger.Info($"通灵师建立联系:{pc.GetNameWithRole().RemoveHtmlTags()} => {target.PlayerName}", "Mediumshiper"); + Logger.Info($"Medium Connection:{pc.GetNameWithRole().RemoveHtmlTags()} => {target.PlayerName}", "Mediumshiper"); } } public static bool MsMsg(PlayerControl pc, string msg) diff --git a/Roles/Crewmate/NiceHacker.cs b/Roles/Crewmate/NiceHacker.cs index dd3e2ee70..417251049 100644 --- a/Roles/Crewmate/NiceHacker.cs +++ b/Roles/Crewmate/NiceHacker.cs @@ -1,5 +1,6 @@ namespace TOHE.Roles.Crewmate { + using Hazel; using System; using System.Collections.Generic; using System.Linq; @@ -60,6 +61,22 @@ else UseLimitSeconds.Add(playerId, UseLimitOpt.GetInt() * ModdedClientAbilityUseSecondsMultiplier.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, float secondsLeft) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetNiceHackerLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(secondsLeft); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + float secondsLeft = reader.ReadSingle(); + + UseLimitSeconds[playerId] = secondsLeft; + } public static void OnEnterVent(PlayerControl pc) { if (pc == null) return; @@ -117,6 +134,7 @@ if (UseLimitSeconds[pc.PlayerId] >= 1) { UseLimitSeconds[pc.PlayerId] -= 1; // Remove 1s for opening the map, so they can't utilize spamming + SendRPC(pc.PlayerId, UseLimitSeconds[pc.PlayerId]); opts.Mode = MapOptions.Modes.CountOverlay; _ = new LateTask(() => { MapCountdown(pc, map, opts, (int)UseLimitSeconds[pc.PlayerId]); }, 1f, "NiceHacker.StartCountdown"); } @@ -142,6 +160,7 @@ return; } UseLimitSeconds[pc.PlayerId] -= 1; + SendRPC(pc.PlayerId, UseLimitSeconds[pc.PlayerId]); _ = new LateTask(() => { MapCountdown(pc, map, opts, seconds - 1); }, 1f, "NiceHackerAbilityCountdown"); } public static string GetHudText(PlayerControl pc) diff --git a/Roles/Crewmate/Oracle.cs b/Roles/Crewmate/Oracle.cs index f10634e6a..ece134690 100644 --- a/Roles/Crewmate/Oracle.cs +++ b/Roles/Crewmate/Oracle.cs @@ -1,3 +1,4 @@ +using Hazel; using System.Collections.Generic; using System.Linq; using static TOHE.Options; @@ -45,6 +46,23 @@ public static class Oracle CheckLimit.TryAdd(playerId, CheckLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetOracleLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) CheckLimit[playerId]--; + else CheckLimit[playerId]++; + } public static void OnVote(PlayerControl player, PlayerControl target) { if (player == null || target == null) return; @@ -58,6 +76,7 @@ public static class Oracle } CheckLimit[player.PlayerId] -= 1; + SendRPC(player.PlayerId, true); if (player.PlayerId == target.PlayerId) { diff --git a/Roles/Crewmate/ParityCop.cs b/Roles/Crewmate/ParityCop.cs index b463282d5..3fdf6d53b 100644 --- a/Roles/Crewmate/ParityCop.cs +++ b/Roles/Crewmate/ParityCop.cs @@ -20,8 +20,6 @@ public static class ParityCop "EgoistCountMode.Neutral", }; - - private static OptionItem TryHideMsg; public static OptionItem ParityCheckLimitMax; public static OptionItem ParityCheckLimitPerMeeting; @@ -32,7 +30,6 @@ public static class ParityCop public static OptionItem ParityCheckRevealTargetTeam; public static OptionItem ParityAbilityUseGainWithEachTaskCompleted; - public static void SetupCustomOption() { SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.ParityCop); @@ -328,15 +325,16 @@ public static class ParityCop { Logger.Msg($"Click: ID {playerId}", "Inspector UI"); var pc = Utils.GetPlayerById(playerId); + var lpcId = PlayerControl.LocalPlayer.PlayerId; if (pc == null || !pc.IsAlive() || !GameStates.IsVoting || !AmongUsClient.Instance.AmHost) return; - if (FirstPick.TryGetValue(PlayerControl.LocalPlayer.PlayerId, out var firstPick)) + if (FirstPick.TryGetValue(lpcId, out var firstPick)) { ParityCheckMsg(PlayerControl.LocalPlayer, $"/cp {playerId} {firstPick}", true); - FirstPick.Remove(PlayerControl.LocalPlayer.PlayerId); + FirstPick.Remove(lpcId); } else { - FirstPick.Add(PlayerControl.LocalPlayer.PlayerId, playerId); + FirstPick.Add(lpcId, playerId); } } diff --git a/Roles/Crewmate/Ricochet.cs b/Roles/Crewmate/Ricochet.cs index 7b24a6838..da603592a 100644 --- a/Roles/Crewmate/Ricochet.cs +++ b/Roles/Crewmate/Ricochet.cs @@ -1,5 +1,6 @@ namespace TOHE.Roles.Crewmate { + using Hazel; using System; using System.Collections.Generic; using System.Linq; @@ -39,6 +40,35 @@ namespace TOHE.Roles.Crewmate UseLimit.Add(playerId, UseLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetRicochetLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendRPCSyncTarget(byte targetId) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetRicochetTarget, SendOption.Reliable, -1); + writer.Write(targetId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) UseLimit[playerId]--; + else UseLimit[playerId]++; + } + public static void ReceiveRPCSyncTarget(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + ProtectAgainst = reader.ReadByte(); + } public static bool OnKillAttempt(PlayerControl killer, PlayerControl target) { if (killer == null) return false; @@ -64,11 +94,14 @@ namespace TOHE.Roles.Crewmate { UseLimit[pc.PlayerId] -= 1; ProtectAgainst = target.PlayerId; + SendRPC(pc.PlayerId, true); + SendRPCSyncTarget(ProtectAgainst); } } public static void OnReportDeadBody() { ProtectAgainst = byte.MaxValue; + SendRPCSyncTarget(ProtectAgainst); } public static string GetProgressText(byte playerId, bool comms) { diff --git a/Roles/Crewmate/SabotageMaster.cs b/Roles/Crewmate/SabotageMaster.cs index 0ae04a5a6..0ab98d641 100644 --- a/Roles/Crewmate/SabotageMaster.cs +++ b/Roles/Crewmate/SabotageMaster.cs @@ -1,3 +1,4 @@ +using Hazel; using System.Collections.Generic; using System.Linq; @@ -23,7 +24,7 @@ public static class SabotageMaster public static void SetupCustomOption() { - Options.SetupRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.SabotageMaster); + Options.SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.SabotageMaster, 1); SkillLimit = IntegerOptionItem.Create(Id + 10, "SabotageMasterSkillLimit", new(0, 80, 1), 2, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]) .SetValueFormat(OptionFormat.Times); FixesDoors = BooleanOptionItem.Create(Id + 11, "SabotageMasterFixesDoors", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.SabotageMaster]); @@ -51,6 +52,18 @@ public static class SabotageMaster playerIdList.Add(playerId); } public static bool IsEnable() => playerIdList.Any(); + public static void SendRPC(float count) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetSabotageMasterLimit, SendOption.Reliable, -1); + writer.Write(count); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + UsedSkillCount = reader.ReadSingle(); + } public static void RepairSystem(ShipStatus __instance, SystemTypes systemType, byte amount) { switch (systemType) @@ -63,6 +76,7 @@ public static class SabotageMaster ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 16); ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Reactor, 17); UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat(); + SendRPC(UsedSkillCount); } break; case SystemTypes.Laboratory: @@ -73,6 +87,7 @@ public static class SabotageMaster ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 67); ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Laboratory, 66); UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat(); + SendRPC(UsedSkillCount); } break; case SystemTypes.LifeSupp: @@ -83,6 +98,7 @@ public static class SabotageMaster ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 67); ShipStatus.Instance.RpcUpdateSystem(SystemTypes.LifeSupp, 66); UsedSkillCount += UsesUsedWhenFixingReactorOrO2.GetFloat(); + SendRPC(UsedSkillCount); } break; case SystemTypes.Comms: @@ -93,6 +109,7 @@ public static class SabotageMaster ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 16); ShipStatus.Instance.RpcUpdateSystem(SystemTypes.Comms, 17); UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat(); + SendRPC(UsedSkillCount); } break; case SystemTypes.Doors: @@ -137,6 +154,7 @@ public static class SabotageMaster __instance.ActualSwitches = 0; __instance.ExpectedSwitches = 0; UsedSkillCount += UsesUsedWhenFixingLightsOrComms.GetFloat(); + SendRPC(UsedSkillCount); } } } \ No newline at end of file diff --git a/Roles/Crewmate/Spy.cs b/Roles/Crewmate/Spy.cs index db2fcddec..e2a1ae0d6 100644 --- a/Roles/Crewmate/Spy.cs +++ b/Roles/Crewmate/Spy.cs @@ -1,5 +1,6 @@ namespace TOHE.Roles.Crewmate { + using Hazel; using System; using System.Collections.Generic; using System.Linq; @@ -12,6 +13,7 @@ namespace TOHE.Roles.Crewmate { private static readonly int Id = 640400; private static List playerIdList = new(); + public static bool change = false; public static Dictionary UseLimit = new(); public static Dictionary SpyRedNameList = new(); @@ -35,6 +37,7 @@ namespace TOHE.Roles.Crewmate playerIdList = new(); UseLimit = new(); SpyRedNameList = new(); + change = false; } public static void Add(byte playerId) { @@ -42,6 +45,48 @@ namespace TOHE.Roles.Crewmate UseLimit.Add(playerId, UseLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte susId) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SpyRedNameSync, SendOption.Reliable, -1); + writer.Write(susId); + writer.Write(SpyRedNameList[susId].ToString()); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendAbilityRPC(byte spyId) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SpyAbilitySync, SendOption.Reliable, -1); + writer.Write(spyId); + writer.Write(UseLimit[spyId]); + AmongUsClient.Instance.FinishRpcImmediately(writer); + + } + public static void SendRPC(byte susId, bool changeColor) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SpyRedNameRemove, SendOption.Reliable, -1); + //writer.Write(spyId); + writer.Write(susId); + writer.Write(changeColor); + TOHE.Logger.Info($"RPC to remove player {susId} from red name list and change `change` to {changeColor}", "Spy"); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader, bool isRemove = false, bool isAbility = false) + { + if (isAbility) + { + byte spyId = reader.ReadByte(); + UseLimit[spyId] = reader.ReadSingle(); + return; + } + else if (isRemove) + { + SpyRedNameList.Remove(reader.ReadByte()); + change = reader.ReadBoolean(); + return; + } + byte susId = reader.ReadByte(); + string stimeStamp = reader.ReadString(); + if (long.TryParse(stimeStamp, out long timeStamp)) SpyRedNameList[susId] = timeStamp; + } public static void OnKillAttempt(PlayerControl killer, PlayerControl target) { if (killer == null) return; @@ -52,7 +97,9 @@ namespace TOHE.Roles.Crewmate if (UseLimit[target.PlayerId] >= 1) { UseLimit[target.PlayerId] -= 1; + SendAbilityRPC(target.PlayerId); SpyRedNameList.TryAdd(killer.PlayerId, GetTimeStamp()); + SendRPC(killer.PlayerId); NotifyRoles(SpecifySeer: target); } } @@ -70,6 +117,7 @@ namespace TOHE.Roles.Crewmate { SpyRedNameList.Remove(x.Key); change = true; + SendRPC(x.Key, change); } } diff --git a/Roles/Crewmate/Tether.cs b/Roles/Crewmate/Tether.cs index fba2caf00..b8096646d 100644 --- a/Roles/Crewmate/Tether.cs +++ b/Roles/Crewmate/Tether.cs @@ -1,5 +1,6 @@ namespace TOHE.Roles.Crewmate { + using Hazel; using System; using System.Collections.Generic; using System.Linq; @@ -42,6 +43,35 @@ namespace TOHE.Roles.Crewmate UseLimit.Add(playerId, UseLimitOpt.GetInt()); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte playerId, bool isMinus) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetTetherLimit, SendOption.Reliable, -1); + writer.Write(playerId); + writer.Write(isMinus); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendRPCSyncTarget(byte targetId) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetTetherTarget, SendOption.Reliable, -1); + writer.Write(targetId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + byte playerId = reader.ReadByte(); + bool isMinus = reader.ReadBoolean(); + + if (isMinus) UseLimit[playerId]--; + else UseLimit[playerId]++; + } + public static void ReceiveRPCSyncTarget(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + Target = reader.ReadByte(); + } public static void OnEnterVent(PlayerControl pc, int ventId, bool isPet = false) { if (pc == null) return; @@ -77,11 +107,14 @@ namespace TOHE.Roles.Crewmate { UseLimit[pc.PlayerId] -= 1; Target = target.PlayerId; + SendRPC(pc.PlayerId, true); + SendRPCSyncTarget(Target); } } public static void OnReportDeadBody() { Target = byte.MaxValue; + SendRPCSyncTarget(Target); } public static string GetProgressText(byte playerId, bool comms) { diff --git a/Roles/Crewmate/Tracker.cs b/Roles/Crewmate/Tracker.cs index 11bbb9f25..d6da79fa0 100644 --- a/Roles/Crewmate/Tracker.cs +++ b/Roles/Crewmate/Tracker.cs @@ -70,7 +70,6 @@ namespace TOHE.Roles.Crewmate TrackerTarget[trackerId].Add(targetId); TargetArrow.Add(trackerId, targetId); - } public static string GetTargetMark(PlayerControl seer, PlayerControl target) => !(seer == null || target == null) && TrackerTarget.ContainsKey(seer.PlayerId) && TrackerTarget[seer.PlayerId].Contains(target.PlayerId) ? Utils.ColorString(seer.GetRoleColor(), "◀") : string.Empty; diff --git a/Roles/Impostor/Disperser.cs b/Roles/Impostor/Disperser.cs index 239f8871b..9e3b82996 100644 --- a/Roles/Impostor/Disperser.cs +++ b/Roles/Impostor/Disperser.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using TOHE.Modules; -using UnityEngine; using static TOHE.Options; using static TOHE.Translator; using static TOHE.Utils; @@ -54,8 +53,6 @@ public static class Disperser return; } - var rd = IRandom.Instance; - var vents = Object.FindObjectsOfType(); DisperserLimit[shapeshifter.PlayerId] -= 1; foreach (var pc in PlayerControl.AllPlayerControls) @@ -69,8 +66,7 @@ public static class Disperser } pc.RPCPlayCustomSound("Teleport"); - var vent = vents[rd.Next(0, vents.Count)]; - TP(pc.NetTransform, new Vector2(vent.transform.position.x, vent.transform.position.y)); + pc.TPtoRndVent(); pc.Notify(ColorString(GetRoleColor(CustomRoles.Disperser), string.Format(GetString("TeleportedInRndVentByDisperser"), pc.GetRealName()))); } } diff --git a/Roles/Impostor/Hitman.cs b/Roles/Impostor/Hitman.cs index 4d4b75679..934a46705 100644 --- a/Roles/Impostor/Hitman.cs +++ b/Roles/Impostor/Hitman.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using Hazel; +using System.Collections.Generic; using System.Linq; using static TOHE.Options; using static TOHE.Utils; @@ -40,6 +41,19 @@ namespace TOHE.Roles.Impostor public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte targetId) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetHitmanTarget, SendOption.Reliable, -1); + writer.Write(targetId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + targetId = reader.ReadByte(); + } + public static bool OnCheckMurder(PlayerControl killer, PlayerControl target) { if (killer == null) return false; @@ -48,6 +62,7 @@ namespace TOHE.Roles.Impostor if (target.PlayerId == targetId) { targetId = byte.MaxValue; + SendRPC(targetId); _ = new LateTask(() => { killer.SetKillCooldown(time: SuccessKCD.GetFloat()); @@ -62,6 +77,7 @@ namespace TOHE.Roles.Impostor if (!GetPlayerById(targetId).IsAlive() || GetPlayerById(targetId).Data.Disconnected) { targetId = byte.MaxValue; + SendRPC(targetId); } } @@ -70,6 +86,7 @@ namespace TOHE.Roles.Impostor if (target == null || hitman == null || !shapeshifting || targetId != byte.MaxValue || !target.IsAlive()) return; targetId = target.PlayerId; + SendRPC(targetId); _ = new LateTask(() => { hitman.CmdCheckRevertShapeshift(false); }, 1.5f, "Hitman RpcRevertShapeshift"); } diff --git a/Roles/Impostor/Mastermind.cs b/Roles/Impostor/Mastermind.cs index e376130a3..94ce69a08 100644 --- a/Roles/Impostor/Mastermind.cs +++ b/Roles/Impostor/Mastermind.cs @@ -24,7 +24,7 @@ namespace TOHE.Roles.Impostor public static void SetupCustomOption() { - SetupSingleRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Mastermind, 1); + SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.Mastermind); KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 180f, 2.5f), 25f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Mastermind]) .SetValueFormat(OptionFormat.Seconds); //ManipulateCDOpt = FloatOptionItem.Create(Id + 11, "MastermindCD", new(0f, 180f, 2.5f), 30f, TabGroup.ImpostorRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Mastermind]) @@ -109,7 +109,7 @@ namespace TOHE.Roles.Impostor ManipulatedPlayers.Remove(x.Key); TempKCDs.Remove(x.Key); player.SetRealKiller(GetPlayerById(playerIdList[0])); - Main.PlayerStates[player.PlayerId].deathReason = PlayerState.DeathReason.Suicide; + Main.PlayerStates[x.Key].deathReason = PlayerState.DeathReason.Suicide; player.Kill(player); RPC.PlaySoundRPC(playerIdList[0], Sounds.KillSound); } @@ -146,7 +146,7 @@ namespace TOHE.Roles.Impostor var mastermind = GetPlayerById(playerIdList[0]); mastermind.Notify(GetString("ManipulatedKilled")); - mastermind.SetKillCooldown(time: KillCooldown.GetFloat()); + if (mastermind.killTimer > KillCooldown.GetFloat()) mastermind.SetKillCooldown(time: KillCooldown.GetFloat()); if (target.Is(CustomRoles.Pestilence) || Main.VeteranInProtect.ContainsKey(target.PlayerId) || target.Is(CustomRoles.Mastermind)) { diff --git a/Roles/Neutral/Eclipse.cs b/Roles/Neutral/Eclipse.cs index b6487d5b6..b31cb372c 100644 --- a/Roles/Neutral/Eclipse.cs +++ b/Roles/Neutral/Eclipse.cs @@ -1,4 +1,5 @@ using AmongUs.GameOptions; +using Hazel; using System.Collections.Generic; using System.Linq; using static TOHE.Options; @@ -42,12 +43,25 @@ public static class Eclipse { playerIdList.Add(playerId); Vision = StartVision.GetFloat(); + _ = new LateTask(() => { SendRPC(Vision); }, 8f, "Eclipse Set Vision RPC"); if (!AmongUsClient.Instance.AmHost) return; if (!Main.ResetCamPlayerList.Contains(playerId)) Main.ResetCamPlayerList.Add(playerId); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(float vision) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetEclipseVision, SendOption.Reliable, -1); + writer.Write(vision); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + Vision = reader.ReadSingle(); + } public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static void ApplyGameOptions(IGameOptions opt) { @@ -63,6 +77,10 @@ public static class Eclipse Vision += VisionIncrease.GetFloat(); if (Vision > MaxVision.GetFloat()) Vision = MaxVision.GetFloat(); - if (Vision != currentVision) pc.SyncSettings(); + if (Vision != currentVision) + { + SendRPC(Vision); + pc.SyncSettings(); + } } } diff --git a/Roles/Neutral/Glitch.cs b/Roles/Neutral/Glitch.cs index 98dbb6454..56843e161 100644 --- a/Roles/Neutral/Glitch.cs +++ b/Roles/Neutral/Glitch.cs @@ -1,4 +1,5 @@ using AmongUs.GameOptions; +using Hazel; using System.Collections.Generic; using System.Linq; using System.Text; @@ -73,6 +74,13 @@ public static class Glitch LastHack = ts; LastMimic = ts; + _ = new LateTask(() => + { + SendRPCSyncLongs(LastKill, LastHack, LastMimic); + SendRPCSyncTimers(MimicCDTimer, MimicDurTimer, HackCDTimer, KCDTimer); + SendRPCSyncSS(isShifted); + }, 7f, "Glitch RPCs"); + if (!AmongUsClient.Instance.AmHost) return; if (!Main.ResetCamPlayerList.Contains(playerId)) Main.ResetCamPlayerList.Add(playerId); @@ -83,6 +91,96 @@ public static class Glitch } public static bool IsEnable => playerIdList.Any(); + public static void SendRPCSyncTimers(int mimicCDTimer, int mimicDurTimer, int hackCDTimer, int KCDTimer) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncGlitchTimers, SendOption.Reliable, -1); + writer.Write(mimicCDTimer); + writer.Write(mimicDurTimer); + writer.Write(hackCDTimer); + writer.Write(KCDTimer); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendRPCSyncMimic(int mimicCDTimer, int mimicDurTimer, long lastMimic) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncGlitchMimic, SendOption.Reliable, -1); + writer.Write(mimicCDTimer); + writer.Write(mimicDurTimer); + writer.Write(lastMimic); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendRPCSyncLongs(long lastKill, long lastHack, long lastMimic) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncGlitchLongs, SendOption.Reliable, -1); + writer.Write(lastKill); + writer.Write(lastHack); + writer.Write(lastMimic); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendRPCSyncKill(long lastKill, int KCDtimer) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncGlitchKill, SendOption.Reliable, -1); + writer.Write(lastKill); + writer.Write(KCDtimer); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendRPCSyncHack(long lastHack, int hackCDTimer) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncGlitchHack, SendOption.Reliable, -1); + writer.Write(lastHack); + writer.Write(hackCDTimer); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void SendRPCSyncSS(bool isShifted) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncGlitchSS, SendOption.Reliable, -1); + writer.Write(isShifted); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPCSyncSS(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + isShifted = reader.ReadBoolean(); + } + public static void ReceiveRPCSyncHack(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + LastHack = long.Parse(reader.ReadString()); + HackCDTimer = reader.ReadInt32(); + } + public static void ReceiveRPCSyncKill(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + LastKill = long.Parse(reader.ReadString()); + KCDTimer = reader.ReadInt32(); + } + public static void ReceiveRPCSyncLongs(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + LastKill = long.Parse(reader.ReadString()); + LastHack = long.Parse(reader.ReadString()); + LastMimic = long.Parse(reader.ReadString()); + } + public static void ReceiveRPCSyncMimic(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + MimicCDTimer = reader.ReadInt32(); + MimicDurTimer = reader.ReadInt32(); + LastMimic = long.Parse(reader.ReadString()); + } + public static void ReceiveRPCSyncTimers(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + MimicCDTimer = reader.ReadInt32(); + MimicDurTimer = reader.ReadInt32(); + HackCDTimer = reader.ReadInt32(); + KCDTimer = reader.ReadInt32(); + } public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = 1f; public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); public static void Mimic(PlayerControl pc) @@ -100,9 +198,11 @@ public static class Glitch pc.RpcShapeshift(playerlist[IRandom.Instance.Next(0, playerlist.Count)], false); isShifted = true; + SendRPCSyncSS(isShifted); LastMimic = Utils.GetTimeStamp(); MimicCDTimer = MimicCooldown.GetInt(); MimicDurTimer = MimicDuration.GetInt(); + SendRPCSyncMimic(MimicCDTimer, MimicDurTimer, LastMimic); } catch (System.Exception ex) { @@ -124,12 +224,14 @@ public static class Glitch HackCDTimer = HackCooldown.GetInt(); hackedIdList.TryAdd(target.PlayerId, Utils.GetTimeStamp()); LastHack = Utils.GetTimeStamp(); + SendRPCSyncHack(LastHack, HackCDTimer); } })) { if (KCDTimer > 0) return false; LastKill = Utils.GetTimeStamp(); KCDTimer = KillCooldown.GetInt(); + SendRPCSyncKill(LastKill, KCDTimer); return true; } else return false; @@ -175,8 +277,9 @@ public static class Glitch { try { - player.CmdCheckRevertShapeshift(false); + player.RpcShapeshift(player, false); isShifted = false; + SendRPCSyncSS(isShifted); } catch (System.Exception ex) { @@ -215,6 +318,8 @@ public static class Glitch if ((!NameNotifyManager.Notice.TryGetValue(player.PlayerId, out var a) || a.Item1 != ns) && ns != string.Empty) player.Notify(ns, 1.1f); } + + SendRPCSyncTimers(MimicCDTimer, MimicDurTimer, HackCDTimer, KCDTimer); } public static string GetHudText(PlayerControl player) { @@ -240,5 +345,7 @@ public static class Glitch KCDTimer = 10; HackCDTimer = 10; MimicCDTimer = 10; + SendRPCSyncLongs(LastKill, LastHack, LastMimic); + SendRPCSyncTimers(MimicCDTimer, MimicDurTimer, HackCDTimer, KCDTimer); } } diff --git a/Roles/Neutral/Magician.cs b/Roles/Neutral/Magician.cs index 326308926..5191d6166 100644 --- a/Roles/Neutral/Magician.cs +++ b/Roles/Neutral/Magician.cs @@ -144,9 +144,7 @@ public static class Magician CardId = byte.MaxValue; break; case 3: // TP to random vent - var vents = Object.FindObjectsOfType(); - var vent = vents[IRandom.Instance.Next(0, vents.Count)]; - TP(pc.NetTransform, new Vector2(vent.transform.position.x, vent.transform.position.y)); + pc.TPtoRndVent(); CardId = byte.MaxValue; break; case 4: // Create Rift Maker portal diff --git a/Roles/Neutral/Postman.cs b/Roles/Neutral/Postman.cs index d7cdb1664..f51f138d3 100644 --- a/Roles/Neutral/Postman.cs +++ b/Roles/Neutral/Postman.cs @@ -117,7 +117,7 @@ public static class Postman var sb = new StringBuilder(); sb.AppendLine(baseText); - if (!IsFinished) sb.AppendLine(string.Format(GetString("PostmanGetNewTarget"), Utils.GetPlayerById(Target))); + if (!IsFinished) sb.AppendLine(string.Format(GetString("PostmanGetNewTarget"), Utils.GetPlayerById(Target).GetRealName())); else sb.AppendLine(GetString("PostmanDone")); pc.Notify(sb.ToString()); @@ -127,7 +127,7 @@ public static class Postman { var sb = new StringBuilder(); - if (!IsFinished) sb.AppendLine(string.Format(GetString("PostmanTarget"), Utils.GetPlayerById(Target))); + if (!IsFinished) sb.AppendLine(string.Format(GetString("PostmanTarget"), Utils.GetPlayerById(Target).GetRealName())); else sb.AppendLine(GetString("PostmanDone")); return sb.ToString(); @@ -135,6 +135,6 @@ public static class Postman public static string GetProgressText(byte playerId) { - return !IsFinished ? string.Format(GetString("PostmanTarget"), Utils.GetPlayerById(Target)) : "✓"; + return !IsFinished ? string.Format(GetString("PostmanTarget"), Utils.GetPlayerById(Target).GetRealName()) : "✓"; } } diff --git a/Roles/Neutral/Pyromaniac.cs b/Roles/Neutral/Pyromaniac.cs index 9646c4b81..34f75bb66 100644 --- a/Roles/Neutral/Pyromaniac.cs +++ b/Roles/Neutral/Pyromaniac.cs @@ -52,7 +52,7 @@ public static class Pyromaniac if (DousedList.Contains(target.PlayerId)) { - new LateTask(() => { killer.SetKillCooldown(BurnCooldown.GetFloat()); }, 0.1f); + _ = new LateTask(() => { killer.SetKillCooldown(BurnCooldown.GetFloat()); }, 0.1f); return true; } else diff --git a/Roles/Neutral/Romantic.cs b/Roles/Neutral/Romantic.cs index 72b028df8..ba9bebec4 100644 --- a/Roles/Neutral/Romantic.cs +++ b/Roles/Neutral/Romantic.cs @@ -171,7 +171,7 @@ public static class Romantic { var player = Utils.GetPlayerById(playerId); if (player == null) return null; - return Utils.ColorString(BetTimes.TryGetValue(playerId, out var timesV1) && timesV1 >= 1 ? Color.white : Utils.GetRoleColor(CustomRoles.Romantic), $"- {(BetTimes.TryGetValue(playerId, out var timesV2) && timesV2 >= 1 && timesV2 >= 1 ? "PICK PARTNER" : "PROTECT PARTNER")}"); + return Utils.ColorString(BetTimes.TryGetValue(playerId, out var timesV1) && timesV1 >= 1 ? Color.white : Utils.GetRoleColor(CustomRoles.Romantic), $"- {(BetTimes.TryGetValue(playerId, out var timesV2) && timesV2 >= 1 && timesV2 >= 1 ? "PICK PARTNER" : "♥")}"); } public static void OnReportDeadBody() { @@ -257,6 +257,7 @@ public static class VengefulRomantic if (VengefulTarget.TryGetValue(killer.PlayerId, out var PartnerKiller) && target.PlayerId == PartnerKiller) { hasKilledKiller = true; + Utils.NotifyRoles(SpecifySeer: killer); return true; } else @@ -270,7 +271,7 @@ public static class VengefulRomantic { var player = Utils.GetPlayerById(playerId); if (player == null) return null; - return Utils.ColorString(hasKilledKiller ? Color.green : Utils.GetRoleColor(CustomRoles.VengefulRomantic), $"- {(hasKilledKiller ? "AVEGNGE SUCCESSFUL" : "AVENGE YOUR PARTNER")}"); + return Utils.ColorString(hasKilledKiller ? Color.green : Utils.GetRoleColor(CustomRoles.VengefulRomantic), $"- {(hasKilledKiller ? "✓" : "☹️")}"); } public static void SendRPC(byte playerId) { diff --git a/Roles/Neutral/Vengeance.cs b/Roles/Neutral/Vengeance.cs index 107297958..578876a95 100644 --- a/Roles/Neutral/Vengeance.cs +++ b/Roles/Neutral/Vengeance.cs @@ -1,7 +1,7 @@ using AmongUs.GameOptions; +using Hazel; using System.Collections.Generic; using System.Linq; -using UnityEngine; using static TOHE.Options; using static TOHE.Translator; @@ -20,7 +20,7 @@ public static class Vengeance private static bool IsRevenge; private static int Timer; private static bool Success; - private static PlayerControl Killer; + private static byte Killer; private static float tempKillTimer; public static void SetupCustomOption() @@ -38,19 +38,50 @@ public static class Vengeance playerIdList = new(); IsRevenge = false; Success = false; - Killer = null; + Killer = byte.MaxValue; tempKillTimer = 0; } public static void Add(byte playerId) { playerIdList.Add(playerId); Timer = RevengeTime.GetInt(); + _ = new LateTask(() => { SendRPCSyncTimer(Timer); }, 8f, "Vengeance Set Timer RPC"); if (!AmongUsClient.Instance.AmHost) return; if (!Main.ResetCamPlayerList.Contains(playerId)) Main.ResetCamPlayerList.Add(playerId); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPCSyncTimer(int timer) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncVengeanceTimer, SendOption.Reliable, -1); + writer.Write(timer); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPCSyncTimer(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + Timer = reader.ReadInt32(); + } + public static void SendRPC(bool isRevenge, bool success, byte killer, float tempKillTimer) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SyncVengeanceData, SendOption.Reliable, -1); + writer.Write(isRevenge); + writer.Write(success); + writer.Write(killer); + writer.Write(tempKillTimer); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + IsRevenge = reader.ReadBoolean(); + Success = reader.ReadBoolean(); + Killer = reader.ReadByte(); + tempKillTimer = reader.ReadSingle(); + } public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); public static bool OnKillAttempt(PlayerControl killer, PlayerControl target) @@ -60,10 +91,7 @@ public static class Vengeance if (target == null) return false; if (IsRevenge) return true; - var rd = IRandom.Instance; - var vents = Object.FindObjectsOfType(); - var vent = vents[rd.Next(0, vents.Count)]; - _ = new LateTask(() => { Utils.TP(target.NetTransform, new Vector2(vent.transform.position.x, vent.transform.position.y)); }, 0.01f); + _ = new LateTask(target.TPtoRndVent, 0.01f); Timer = RevengeTime.GetInt(); Countdown(Timer, target); @@ -71,7 +99,9 @@ public static class Vengeance killer.SetKillCooldown(); tempKillTimer = target.killTimer; target.SetKillCooldown(time: 1f); - Killer = killer; + Killer = killer.PlayerId; + + SendRPC(IsRevenge, Success, Killer, tempKillTimer); return false; } @@ -82,11 +112,14 @@ public static class Vengeance { Timer = RevengeTime.GetInt(); Success = false; + SendRPCSyncTimer(Timer); + SendRPC(IsRevenge, Success, Killer, tempKillTimer); return; } if ((seconds <= 0 || GameStates.IsMeeting) && player.IsAlive()) { player.Kill(player); return; } player.Notify(string.Format(GetString("VengeanceRevenge"), seconds), 1.1f); Timer = seconds; + SendRPCSyncTimer(Timer); _ = new LateTask(() => { Countdown(seconds - 1, player); }, 1.01f); } @@ -96,12 +129,13 @@ public static class Vengeance if (target == null) return false; if (!IsRevenge) return true; - else if (target == Killer) + else if (target.PlayerId == Killer) { Success = true; killer.Notify(GetString("VengeanceSuccess")); killer.SetKillCooldown(KillCooldown.GetFloat() + tempKillTimer); IsRevenge = false; + SendRPC(IsRevenge, Success, Killer, tempKillTimer); return true; } else diff --git a/Roles/Neutral/WeaponMaster.cs b/Roles/Neutral/WeaponMaster.cs index bc874ade0..e22b949ee 100644 --- a/Roles/Neutral/WeaponMaster.cs +++ b/Roles/Neutral/WeaponMaster.cs @@ -1,4 +1,5 @@ using AmongUs.GameOptions; +using Hazel; using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -54,6 +55,20 @@ public static class WeaponMaster Main.ResetCamPlayerList.Add(playerId); } public static bool IsEnable => playerIdList.Any(); + public static void SendRPC(byte mode, bool shieldUsed) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetWeaponMasterMode, SendOption.Reliable, -1); + writer.Write(mode); + writer.Write(shieldUsed); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + public static void ReceiveRPC(MessageReader reader) + { + if (AmongUsClient.Instance.AmHost) return; + + Mode = reader.ReadByte(); + shieldUsed = reader.ReadBoolean(); + } public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static void ApplyGameOptions(IGameOptions opt) { @@ -86,6 +101,8 @@ public static class WeaponMaster WM.Notify(Translator.GetString("WMShieldAlreadyUsed")); break; } + + SendRPC(Mode, shieldUsed); WM.MarkDirtySettings(); } public static bool OnCheckMurder(PlayerControl killer, PlayerControl target) @@ -134,6 +151,7 @@ public static class WeaponMaster if (Mode == 3 && !shieldUsed) { shieldUsed = true; + SendRPC(Mode, shieldUsed); return true; } else return false; diff --git a/TOHE.csproj b/TOHE.csproj index 661b09ea5..2b27883d1 100644 --- a/TOHE.csproj +++ b/TOHE.csproj @@ -18,6 +18,8 @@ + + diff --git a/main.cs b/main.cs index fe9ef3309..634e6412e 100644 --- a/main.cs +++ b/main.cs @@ -33,8 +33,8 @@ public class Main : BasePlugin public static ConfigEntry DebugKeyInput { get; private set; } public static readonly string MainMenuText = " "; public const string PluginGuid = "com.gurge44.toheplus"; - public const string PluginVersion = "1.2.0"; - public const string PluginDisplayVersion = "1.2.0"; + public const string PluginVersion = "1.2.1"; + public const string PluginDisplayVersion = "1.2.1"; public static readonly string SupportedAUVersion = "2023.10.24"; public const int PluginCreate = 3; public const bool Canary = false;