From 8bffe93f0477174105c7def12da3f90dc7e3158d Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Sun, 15 Oct 2023 21:05:13 +0200 Subject: [PATCH] Finish Magician --- .editorconfig | 132 +++++++ Modules/ErrorText.cs | 26 +- .../PlayerGameOptionsSender.cs | 7 + Modules/GuessManager.cs | 8 +- Modules/OptionHolder.cs | 6 +- Modules/RPC.cs | 2 +- Modules/Utils.cs | 204 +++------- Patches/HudPatch.cs | 5 +- Patches/PetActionsPatch.cs | 5 +- Patches/PlayerContorolPatch.cs | 15 +- Patches/ShipStatusPatch.cs | 5 + Resources/String.csv | 42 ++ Roles/Crewmate/CameraMan.cs | 2 +- Roles/Crewmate/Farseer.cs | 5 +- Roles/Crewmate/Judge.cs | 12 +- Roles/Crewmate/Monarch.cs | 12 +- Roles/Neutral/Agitater.cs | 2 +- Roles/Neutral/Bandit.cs | 2 +- Roles/Neutral/Infectious.cs | 12 +- Roles/Neutral/Mafioso.cs | 16 +- Roles/Neutral/Magician.cs | 368 +++++++++++++++++- Roles/Neutral/NSerialKiller.cs | 6 - Roles/Neutral/Postman.cs | 16 +- Roles/Neutral/Reckless.cs | 6 +- main.cs | 4 +- 25 files changed, 685 insertions(+), 235 deletions(-) diff --git a/.editorconfig b/.editorconfig index f694b8276..2304f7ccb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,3 +2,135 @@ # CA2211: Non-constant fields should not be visible dotnet_diagnostic.CA2211.severity = none + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = none +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_indent_labels = one_less_than_current +csharp_style_throw_expression = true:suggestion +csharp_style_prefer_null_check_over_type_check = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion +csharp_style_prefer_index_operator = true:suggestion +csharp_style_prefer_range_operator = true:suggestion +csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_unused_value_assignment_preference = discard_variable:suggestion +csharp_style_unused_value_expression_statement_preference = discard_variable:silent +csharp_prefer_static_local_function = true:suggestion +csharp_style_prefer_readonly_struct = true:suggestion +csharp_style_prefer_readonly_struct_member = true:suggestion +csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent +csharp_style_var_elsewhere = false:silent + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_readonly_field = true:suggestion +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_allow_multiple_blank_lines_experimental = true:silent +dotnet_style_allow_statement_immediately_after_block_experimental = true:silent +dotnet_code_quality_unused_parameters = all:suggestion +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent diff --git a/Modules/ErrorText.cs b/Modules/ErrorText.cs index d34d382bd..8c399433d 100644 --- a/Modules/ErrorText.cs +++ b/Modules/ErrorText.cs @@ -15,19 +15,19 @@ public class ErrorText : MonoBehaviour return _instance; } } - private static readonly ErrorText _instance; - //private void Awake() - //{ - // if (_instance != null) - // { - // Destroy(gameObject); - // } - // else - // { - // _instance = this; - // DontDestroyOnLoad(this); - // } - //} + private static ErrorText _instance; + private void Awake() + { + if (_instance != null) + { + Destroy(gameObject); + } + else + { + _instance = this; + DontDestroyOnLoad(this); + } + } #endregion public static void Create(TMPro.TextMeshPro baseText) { diff --git a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs index c8be4fea7..d311360be 100644 --- a/Modules/GameOptionsSender/PlayerGameOptionsSender.cs +++ b/Modules/GameOptionsSender/PlayerGameOptionsSender.cs @@ -646,6 +646,13 @@ public class PlayerGameOptionsSender : GameOptionsSender } } + if (Magician.BlindPPL.ContainsKey(player.PlayerId)) + { + opt.SetVision(false); + opt.SetFloat(FloatOptionNames.CrewLightMod, 0.01f); + opt.SetFloat(FloatOptionNames.ImpostorLightMod, 0.01f); + } + // ������������ȴΪ0ʱ�޷�������ʾͼ�� AURoleOptions.EngineerCooldown = Mathf.Max(0.01f, AURoleOptions.EngineerCooldown); diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index 5914978ef..3e9727d93 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -654,9 +654,9 @@ public static class GuessManager return true; } - public static TextMeshPro nameText(this PlayerControl p) => p.cosmetics.nameText; + public static TextMeshPro NameText(this PlayerControl p) => p.cosmetics.nameText; public static TextMeshPro NameText(this PoolablePlayer p) => p.cosmetics.nameText; - public static void RpcGuesserMurderPlayer(this PlayerControl pc, float delay = 0f) //ゲッサー用の殺し方 + public static void RpcGuesserMurderPlayer(this PlayerControl pc/*, float delay = 0f*/) //ゲッサー用の殺し方 { // DEATH STUFF // var amOwner = pc.AmOwner; @@ -670,7 +670,7 @@ public static class GuessManager if (amOwner) { hudManager.ShadowQuad.gameObject.SetActive(false); - pc.nameText().GetComponent().material.SetInt("_Mask", 0); + pc.NameText().GetComponent().material.SetInt("_Mask", 0); pc.RpcSetScanner(false); ImportantTextTask importantTextTask = new GameObject("_Player").AddComponent(); importantTextTask.transform.SetParent(AmongUsClient.Instance.transform, false); @@ -709,7 +709,7 @@ public static class GuessManager if (amOwner) { hudManager.ShadowQuad.gameObject.SetActive(false); - pc.nameText().GetComponent().material.SetInt("_Mask", 0); + pc.NameText().GetComponent().material.SetInt("_Mask", 0); pc.RpcSetScanner(false); ImportantTextTask importantTextTask = new GameObject("_Player").AddComponent(); importantTextTask.transform.SetParent(AmongUsClient.Instance.transform, false); diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index a69d3aa68..c07d2dd68 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -1805,13 +1805,13 @@ public static class Options NSerialKiller.SetupCustomOption(); RoleLoadingText = "Neutral roles\nPostman"; - Postman.SetupCustomOption(); + //Postman.SetupCustomOption(); RoleLoadingText = "Neutral roles\nReckless"; - Reckless.SetupCustomOption(); + //Reckless.SetupCustomOption(); RoleLoadingText = "Neutral roles\nMagician"; Magician.SetupCustomOption(); RoleLoadingText = "Neutral roles\nMafioso"; - Mafioso.SetupCustomOption(); + //Mafioso.SetupCustomOption(); RoleLoadingText = "Neutral roles\nPyromaniac"; Pyromaniac.SetupCustomOption(); RoleLoadingText = "Neutral roles\nEclipse"; diff --git a/Modules/RPC.cs b/Modules/RPC.cs index da3f31fc3..e8dd3fbef 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -196,7 +196,7 @@ internal class RPCHandlerPatch } return false; } - if (ReportDeadBodyRPCs[__instance.PlayerId] > 4) + if (ReportDeadBodyRPCs.TryGetValue(__instance.PlayerId, out var times) && times > 4) { AmongUsClient.Instance.KickPlayer(__instance.GetClientId(), true); Logger.SendInGame(string.Format(GetString("Warning.ReportDeadBodyHack"), __instance?.Data?.PlayerName)); diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 67dd02fea..b723a238f 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -1,5 +1,6 @@ using AmongUs.Data; using AmongUs.GameOptions; +using Epic.OnlineServices; using Hazel; using Il2CppInterop.Runtime.InteropTypes; using InnerNet; @@ -617,7 +618,6 @@ public static class Utils var role = Main.PlayerStates[playerId].MainRole; try { - switch (role) { case CustomRoles.Arsonist: @@ -710,232 +710,128 @@ public static class Utils ProgressText.Append(Jailor.GetProgressText(playerId)); break; case CustomRoles.NiceSwapper: + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(NiceSwapper.GetNiceSwappermax(playerId)); break; case CustomRoles.Veteran: - var taskState2 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor2; - var TaskCompleteColor2 = Color.green; - var NonCompleteColor2 = Color.yellow; - var NormalColor2 = taskState2.IsTaskFinished ? TaskCompleteColor2 : NonCompleteColor2; - TextColor2 = comms ? Color.gray : NormalColor2; - string Completed2 = comms ? "?" : $"{taskState2.CompletedTasksCount}"; Color TextColor21; if (Main.VeteranNumOfUsed[playerId] < 1) TextColor21 = Color.red; else if (Main.VeteranInProtect.ContainsKey(playerId)) TextColor21 = Color.green; else TextColor21 = Color.white; - ProgressText.Append(ColorString(TextColor2, $"- {Completed2}/{taskState2.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor21, $" - {Math.Round(Main.VeteranNumOfUsed[playerId], 1)}")); if (Options.UsePets.GetBool() && Main.VeteranCD.TryGetValue(playerId, out var time2) && !GetPlayerById(playerId).IsModClient()) ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.VeteranSkillCooldown.GetInt() + Options.VeteranSkillDuration.GetInt() - (GetTimeStamp() - time2) + 1)); break; case CustomRoles.Grenadier: - var taskState3 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor3; - var TaskCompleteColor3 = Color.green; - var NonCompleteColor3 = Color.yellow; - var NormalColor3 = taskState3.IsTaskFinished ? TaskCompleteColor3 : NonCompleteColor3; - TextColor3 = comms ? Color.gray : NormalColor3; - string Completed3 = comms ? "?" : $"{taskState3.CompletedTasksCount}"; Color TextColor31; if (Main.GrenadierNumOfUsed[playerId] < 1) TextColor31 = Color.red; else if (Main.GrenadierBlinding.ContainsKey(playerId)) TextColor31 = Color.green; else TextColor31 = Color.white; - ProgressText.Append(ColorString(TextColor3, $"- {Completed3}/{taskState3.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor31, $" - {Math.Round(Main.GrenadierNumOfUsed[playerId], 1)}")); if (Options.UsePets.GetBool() && Main.GrenadierCD.TryGetValue(playerId, out var time3) && !GetPlayerById(playerId).IsModClient()) ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.GrenadierSkillCooldown.GetInt() + Options.GrenadierSkillDuration.GetInt() - (GetTimeStamp() - time3) + 1)); break; case CustomRoles.Divinator: - var taskState4 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor4; - var TaskCompleteColor4 = Color.green; - var NonCompleteColor4 = Color.yellow; - var NormalColor4 = taskState4.IsTaskFinished ? TaskCompleteColor4 : NonCompleteColor4; - TextColor4 = comms ? Color.gray : NormalColor4; - string Completed4 = comms ? "?" : $"{taskState4.CompletedTasksCount}"; Color TextColor41; if (Divinator.CheckLimit[playerId] < 1) TextColor41 = Color.red; else TextColor41 = Color.white; - ProgressText.Append(ColorString(TextColor4, $"- {Completed4}/{taskState4.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor41, $" - {Math.Round(Divinator.CheckLimit[playerId])}")); break; case CustomRoles.DovesOfNeace: - var taskState5 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor5; - var TaskCompleteColor5 = Color.green; - var NonCompleteColor5 = Color.yellow; - var NormalColor5 = taskState5.IsTaskFinished ? TaskCompleteColor5 : NonCompleteColor5; - TextColor5 = comms ? Color.gray : NormalColor5; - string Completed5 = comms ? "?" : $"{taskState5.CompletedTasksCount}"; Color TextColor51; if (Main.DovesOfNeaceNumOfUsed[playerId] < 1) TextColor51 = Color.red; else TextColor51 = Color.white; - ProgressText.Append(ColorString(TextColor5, $"- {Completed5}/{taskState5.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor51, $" - {Math.Round(Main.DovesOfNeaceNumOfUsed[playerId], 1)}")); if (Options.UsePets.GetBool() && Main.DovesOfNeaceCD.TryGetValue(playerId, out var time4) && !GetPlayerById(playerId).IsModClient()) ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.DovesOfNeaceCooldown.GetInt() - (GetTimeStamp() - time4) + 1)); break; case CustomRoles.TimeMaster: - var taskState6 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor6; - var TaskCompleteColor6 = Color.green; - var NonCompleteColor6 = Color.yellow; - var NormalColor6 = taskState6.IsTaskFinished ? TaskCompleteColor6 : NonCompleteColor6; - TextColor6 = comms ? Color.gray : NormalColor6; - string Completed6 = comms ? "?" : $"{taskState6.CompletedTasksCount}"; Color TextColor61; if (Main.TimeMasterNumOfUsed[playerId] < 1) TextColor61 = Color.red; else if (Main.TimeMasterInProtect.ContainsKey(playerId)) TextColor61 = Color.green; else TextColor61 = Color.white; - ProgressText.Append(ColorString(TextColor6, $"- {Completed6}/{taskState6.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor61, $" - {Math.Round(Main.TimeMasterNumOfUsed[playerId], 1)}")); if (Options.UsePets.GetBool() && Main.TimeMasterCD.TryGetValue(playerId, out var time5) && !GetPlayerById(playerId).IsModClient()) ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.TimeMasterSkillCooldown.GetInt() + Options.TimeMasterSkillDuration.GetInt() - (GetTimeStamp() - time5) + 1)); break; case CustomRoles.Mediumshiper: - var taskState7 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor7; - var TaskCompleteColor7 = Color.green; - var NonCompleteColor7 = Color.yellow; - var NormalColor7 = taskState7.IsTaskFinished ? TaskCompleteColor7 : NonCompleteColor7; - TextColor7 = comms ? Color.gray : NormalColor7; - string Completed7 = comms ? "?" : $"{taskState7.CompletedTasksCount}"; Color TextColor71; if (Mediumshiper.ContactLimit[playerId] < 1) TextColor71 = Color.red; else TextColor71 = Color.white; - ProgressText.Append(ColorString(TextColor7, $"- {Completed7}/{taskState7.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor71, $" - {Math.Round(Mediumshiper.ContactLimit[playerId], 1)}")); break; case CustomRoles.ParityCop: - var taskState8 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor8; - var TaskCompleteColor8 = Color.green; - var NonCompleteColor8 = Color.yellow; - var NormalColor8 = taskState8.IsTaskFinished ? TaskCompleteColor8 : NonCompleteColor8; - TextColor8 = comms ? Color.gray : NormalColor8; - string Completed8 = comms ? "?" : $"{taskState8.CompletedTasksCount}"; Color TextColor81; if (ParityCop.MaxCheckLimit[playerId] < 1) TextColor81 = Color.red; else TextColor81 = Color.white; - ProgressText.Append(ColorString(TextColor8, $"- {Completed8}/{taskState8.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor81, $" - {Math.Round(ParityCop.MaxCheckLimit[playerId], 1)}")); break; case CustomRoles.Oracle: - var taskState9 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor9; - var TaskCompleteColor9 = Color.green; - var NonCompleteColor9 = Color.yellow; - var NormalColor9 = taskState9.IsTaskFinished ? TaskCompleteColor9 : NonCompleteColor9; - TextColor9 = comms ? Color.gray : NormalColor9; - string Completed9 = comms ? "?" : $"{taskState9.CompletedTasksCount}"; Color TextColor91; if (Oracle.CheckLimit[playerId] < 1) TextColor91 = Color.red; else TextColor91 = Color.white; - ProgressText.Append(ColorString(TextColor9, $"- {Completed9}/{taskState9.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor91, $" - {Math.Round(Oracle.CheckLimit[playerId], 1)}")); break; case CustomRoles.SabotageMaster: - var taskState10 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor10; - var TaskCompleteColor10 = Color.green; - var NonCompleteColor10 = Color.yellow; - var NormalColor10 = taskState10.IsTaskFinished ? TaskCompleteColor10 : NonCompleteColor10; - TextColor10 = comms ? Color.gray : NormalColor10; - string Completed10 = comms ? "?" : $"{taskState10.CompletedTasksCount}"; Color TextColor101; if (SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount > 1) TextColor101 = Color.red; else TextColor101 = Color.white; - ProgressText.Append(ColorString(TextColor10, $"- {Completed10}/{taskState10.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor101, $" - {Math.Round(SabotageMaster.SkillLimit.GetFloat() - SabotageMaster.UsedSkillCount, 1)}")); break; case CustomRoles.Tracker: - var taskState11 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor11; - var TaskCompleteColor11 = Color.green; - var NonCompleteColor11 = Color.yellow; - var NormalColor11 = taskState11.IsTaskFinished ? TaskCompleteColor11 : NonCompleteColor11; - TextColor11 = comms ? Color.gray : NormalColor11; - string Completed11 = comms ? "?" : $"{taskState11.CompletedTasksCount}"; Color TextColor111; if (Tracker.TrackLimit[playerId] < 1) TextColor111 = Color.red; else TextColor111 = Color.white; - ProgressText.Append(ColorString(TextColor11, $"- {Completed11}/{taskState11.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor111, $" - {Math.Round(Tracker.TrackLimit[playerId], 1)}")); break; case CustomRoles.Bloodhound: - var taskState12 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor12; - var TaskCompleteColor12 = Color.green; - var NonCompleteColor12 = Color.yellow; - var NormalColor12 = taskState12.IsTaskFinished ? TaskCompleteColor12 : NonCompleteColor12; - TextColor12 = comms ? Color.gray : NormalColor12; - string Completed12 = comms ? "?" : $"{taskState12.CompletedTasksCount}"; Color TextColor121; if (Bloodhound.UseLimit[playerId] < 1) TextColor121 = Color.red; else TextColor121 = Color.white; - ProgressText.Append(ColorString(TextColor12, $"- {Completed12}/{taskState12.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor121, $" - {Math.Round(Bloodhound.UseLimit[playerId], 1)}")); break; case CustomRoles.Chameleon: - var taskState13 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor13; - var TaskCompleteColor13 = Color.green; - var NonCompleteColor13 = Color.yellow; - var NormalColor13 = taskState13.IsTaskFinished ? TaskCompleteColor13 : NonCompleteColor13; - TextColor13 = comms ? Color.gray : NormalColor13; - string Completed13 = comms ? "?" : $"{taskState13.CompletedTasksCount}"; Color TextColor131; if (Chameleon.UseLimit[playerId] < 1) TextColor131 = Color.red; else if (Chameleon.IsInvis(playerId)) TextColor131 = Color.green; else TextColor131 = Color.white; - ProgressText.Append(ColorString(TextColor13, $"- {Completed13}/{taskState13.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor131, $" - {Math.Round(Chameleon.UseLimit[playerId], 1)}")); break; case CustomRoles.Lighter: - var taskState14 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor14; - var TaskCompleteColor14 = Color.green; - var NonCompleteColor14 = Color.yellow; - var NormalColor14 = taskState14.IsTaskFinished ? TaskCompleteColor14 : NonCompleteColor14; - TextColor14 = comms ? Color.gray : NormalColor14; - string Completed14 = comms ? "?" : $"{taskState14.CompletedTasksCount}"; Color TextColor141; if (Main.LighterNumOfUsed[playerId] < 1) TextColor141 = Color.red; else if (Main.Lighter.ContainsKey(playerId)) TextColor141 = Color.green; else TextColor141 = Color.white; - ProgressText.Append(ColorString(TextColor14, $"- {Completed14}/{taskState14.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor141, $" - {Math.Round(Main.LighterNumOfUsed[playerId], 1)}")); if (Options.UsePets.GetBool() && Main.LighterCD.TryGetValue(playerId, out var time6) && !GetPlayerById(playerId).IsModClient()) ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.LighterSkillCooldown.GetInt() + Options.LighterSkillDuration.GetInt() - (GetTimeStamp() - time6) + 1)); break; case CustomRoles.Ventguard: - var taskState15 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor15; - var TaskCompleteColor15 = Color.green; - var NonCompleteColor15 = Color.yellow; - var NormalColor15 = taskState15.IsTaskFinished ? TaskCompleteColor15 : NonCompleteColor15; - TextColor15 = comms ? Color.gray : NormalColor15; - string Completed15 = comms ? "?" : $"{taskState15.CompletedTasksCount}"; Color TextColor151; if (Main.VentguardNumberOfAbilityUses < 1) TextColor151 = Color.red; else TextColor151 = Color.white; - ProgressText.Append(ColorString(TextColor15, $"- {Completed15}/{taskState15.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor151, $" - {Math.Round(Main.VentguardNumberOfAbilityUses, 1)}")); break; case CustomRoles.SecurityGuard: - var taskState16 = Main.PlayerStates?[playerId].GetTaskState(); - Color TextColor16; - var TaskCompleteColor16 = Color.green; - var NonCompleteColor16 = Color.yellow; - var NormalColor16 = taskState16.IsTaskFinished ? TaskCompleteColor16 : NonCompleteColor16; - TextColor16 = comms ? Color.gray : NormalColor16; - string Completed16 = comms ? "?" : $"{taskState16.CompletedTasksCount}"; Color TextColor161; if (Main.SecurityGuardNumOfUsed[playerId] < 1) TextColor161 = Color.red; else if (Main.BlockSabo.ContainsKey(playerId)) TextColor161 = Color.green; else TextColor161 = Color.white; - ProgressText.Append(ColorString(TextColor16, $"- {Completed16}/{taskState16.AllTasksCount}")); + ProgressText.Append(GetTaskCount(playerId, comms)); ProgressText.Append(ColorString(TextColor161, $" - {Math.Round(Main.SecurityGuardNumOfUsed[playerId], 1)}")); if (Options.UsePets.GetBool() && Main.SecurityGuardCD.TryGetValue(playerId, out var time7) && !GetPlayerById(playerId).IsModClient()) ProgressText.Append(" " + string.Format(GetString("CDPT"), Options.SecurityGuardSkillCooldown.GetInt() + Options.SecurityGuardSkillDuration.GetInt() - (GetTimeStamp() - time7) + 1)); @@ -1144,37 +1040,45 @@ public static class Utils break; default: //タスクテキスト - var taskState = Main.PlayerStates?[playerId].GetTaskState(); - if (taskState.hasTasks) - { - Color TextColor; - var info = GetPlayerInfoById(playerId); - var TaskCompleteColor = HasTasks(info) ? Color.green : GetRoleColor(role).ShadeColor(0.5f); //タスク完了後の色 - var NonCompleteColor = HasTasks(info) ? Color.yellow : Color.white; //カウントされない人外は白色 - - if (Workhorse.IsThisRole(playerId)) - NonCompleteColor = Workhorse.RoleColor; - - var NormalColor = taskState.IsTaskFinished ? TaskCompleteColor : NonCompleteColor; - if (Main.PlayerStates.TryGetValue(playerId, out var ps) && ps.MainRole == CustomRoles.Crewpostor) - NormalColor = Color.red; - - TextColor = comms ? Color.gray : NormalColor; - string Completed = comms ? "?" : $"{taskState.CompletedTasksCount}"; - ProgressText.Append(ColorString(TextColor, $"- {Completed}/{taskState.AllTasksCount}")); - } + ProgressText.Append(GetTaskCount(playerId, comms)); break; } } catch (Exception ex) { - Logger.Error(ex.ToString(), "Utils.GetProgressText"); + Logger.Error($"For {GetPlayerById(playerId).GetNameWithRole().RemoveHtmlTags()}, failed to get progress text: " + ex.ToString(), "Utils.GetProgressText"); } - if (ProgressText.Length != 0) + if (ProgressText.Length != 0 && !ProgressText.ToString().StartsWith(' ')) ProgressText.Insert(0, " "); //空じゃなければ空白を追加 return ProgressText.ToString(); } + public static string GetTaskCount(byte playerId, bool comms) + { + var taskState = Main.PlayerStates?[playerId].GetTaskState(); + if (taskState.hasTasks) + { + Color TextColor; + var info = GetPlayerInfoById(playerId); + var TaskCompleteColor = HasTasks(info) ? Color.green : GetRoleColor(Main.PlayerStates[playerId].MainRole).ShadeColor(0.5f); //タスク完了後の色 + var NonCompleteColor = HasTasks(info) ? Color.yellow : Color.white; //カウントされない人外は白色 + + if (Workhorse.IsThisRole(playerId)) + NonCompleteColor = Workhorse.RoleColor; + + var NormalColor = taskState.IsTaskFinished ? TaskCompleteColor : NonCompleteColor; + if (Main.PlayerStates.TryGetValue(playerId, out var ps) && ps.MainRole == CustomRoles.Crewpostor) + NormalColor = Color.red; + + TextColor = comms ? Color.gray : NormalColor; + string Completed = comms ? "?" : $"{taskState.CompletedTasksCount}"; + return ColorString(TextColor, $"- {Completed}/{taskState.AllTasksCount}"); + } + else + { + return string.Empty; + } + } public static void ShowActiveSettingsHelp(byte PlayerId = byte.MaxValue) { SendMessage(GetString("CurrentActiveSettingsHelp") + ":", PlayerId); @@ -1192,6 +1096,20 @@ public static class Utils if (Options.NoGameEnd.GetBool()) { SendMessage(GetString("NoGameEndInfo"), PlayerId); } } + public static List GetPlayersInRadius(float radius, Vector2 from) + { + var list = new List(); + foreach (var tg in Main.AllAlivePlayerControls) + { + var dis = Vector2.Distance(from, tg.transform.position); + + if (Pelican.IsEaten(tg.PlayerId) || Medic.ProtectList.Contains(tg.PlayerId) || tg.inVent) continue; + if (dis > radius) continue; + + list.Add(tg); + } + return list; + } public static void ShowActiveSettings(byte PlayerId = byte.MaxValue) { if (Options.HideGameSettings.GetBool() && PlayerId != byte.MaxValue) @@ -1858,9 +1776,7 @@ public static class Utils private static readonly StringBuilder TargetSuffix = new(); private static readonly StringBuilder TargetMark = new(20); -#pragma warning disable IDE0060 // Remove unused parameter public static async void NotifyRoles(bool isForMeeting = false, PlayerControl SpecifySeer = null, bool NoCache = false, bool ForceLoop = false, bool CamouflageIsForMeeting = false, bool GuesserIsForMeeting = false) -#pragma warning restore IDE0060 // Remove unused parameter { //if (Options.DeepLowLoad.GetBool()) await Task.Run(() => { DoNotifyRoles(isForMeeting, SpecifySeer, NoCache, ForceLoop, CamouflageIsForMeeting, GuesserIsForMeeting); }); /*else */ diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index 554522c69..bebfb08b9 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -641,6 +641,9 @@ class SetHudActivePatch case CustomRoles.Glitch: Glitch.SetHudActive(__instance, isActive); break; + case CustomRoles.Magician: + __instance.SabotageButton?.ToggleVisible(true); + break; } @@ -692,7 +695,7 @@ class MapBehaviourShowPatch } else if (opts.Mode is MapOptions.Modes.Normal or MapOptions.Modes.Sabotage) { - if (player.Is(CustomRoleTypes.Impostor) || player.Is(CustomRoles.Glitch) || player.Is(CustomRoles.Parasite) || player.Is(CustomRoles.Refugee) || (player.Is(CustomRoles.Jackal) && Jackal.CanUseSabotage.GetBool()) || (player.Is(CustomRoles.Traitor) && Traitor.CanUseSabotage.GetBool())) + if (player.Is(CustomRoleTypes.Impostor) || player.Is(CustomRoles.Glitch) || player.Is(CustomRoles.Magician) || player.Is(CustomRoles.Parasite) || player.Is(CustomRoles.Refugee) || (player.Is(CustomRoles.Jackal) && Jackal.CanUseSabotage.GetBool()) || (player.Is(CustomRoles.Traitor) && Traitor.CanUseSabotage.GetBool())) opts.Mode = MapOptions.Modes.Sabotage; else opts.Mode = MapOptions.Modes.Normal; diff --git a/Patches/PetActionsPatch.cs b/Patches/PetActionsPatch.cs index 1d52efffe..36eea74f8 100644 --- a/Patches/PetActionsPatch.cs +++ b/Patches/PetActionsPatch.cs @@ -67,7 +67,7 @@ class ExternalRpcPetPatch AmongUsClient.Instance.FinishRpcImmediately(AmongUsClient.Instance.StartRpcImmediately(__instance.NetId, 50, SendOption.None, player.GetClientId())); } - Logger.Info($"Player {pc.GetNameWithRole().RemoveHtmlTags()} has Pet", "RPCDEBUG"); + Logger.Info($"Player {pc.GetNameWithRole().RemoveHtmlTags()} petted their pet", "PetActionTrigger"); OnPetUse(pc); } @@ -510,6 +510,9 @@ class ExternalRpcPetPatch case CustomRoles.Glitch: Glitch.Mimic(pc); break; + case CustomRoles.Magician: + Magician.UseCard(pc); + break; } } } \ No newline at end of file diff --git a/Patches/PlayerContorolPatch.cs b/Patches/PlayerContorolPatch.cs index e4318940a..a46e918b9 100644 --- a/Patches/PlayerContorolPatch.cs +++ b/Patches/PlayerContorolPatch.cs @@ -212,6 +212,9 @@ class CheckMurderPatch case CustomRoles.Reckless: Reckless.OnCheckMurder(killer); break; + case CustomRoles.Magician: + Magician.OnCheckMurder(killer); + break; case CustomRoles.Vengeance: if (!Vengeance.OnCheckMurder(killer, target)) return false; break; @@ -1325,8 +1328,8 @@ class ShapeshiftPatch } _ = new LateTask(() => { - bool totalAlive = Main.AllAlivePlayerControls.Any(); - if (Options.BomberDiesInExplosion.GetBool() && totalAlive && !GameStates.IsEnded) + var totalAlive = Main.AllAlivePlayerControls.Count(); + if (Options.BomberDiesInExplosion.GetBool() && totalAlive > 1 && !GameStates.IsEnded) { Main.PlayerStates[shapeshifter.PlayerId].deathReason = PlayerState.DeathReason.Bombed; shapeshifter.RpcMurderPlayerV3(shapeshifter); @@ -1362,8 +1365,8 @@ class ShapeshiftPatch } _ = new LateTask(() => { - bool totalAlive = Main.AllAlivePlayerControls.Any(); - if (totalAlive && !GameStates.IsEnded) + var totalAlive = Main.AllAlivePlayerControls.Count(); + if (totalAlive > 1 && !GameStates.IsEnded) { Main.PlayerStates[shapeshifter.PlayerId].deathReason = PlayerState.DeathReason.Bombed; shapeshifter.RpcMurderPlayerV3(shapeshifter); @@ -1774,6 +1777,7 @@ class ReportDeadBodyPatch if (Hitman.IsEnable) Hitman.OnReportDeadBody(); if (Gambler.IsEnable) Gambler.OnReportDeadBody(); if (Tracker.IsEnable) Tracker.OnReportDeadBody(); + if (Magician.IsEnable) Magician.OnReportDeadBody(); if (Reckless.IsEnable) Reckless.OnReportDeadBody(); if (Mortician.IsEnable) Mortician.OnReportDeadBody(player, target); @@ -1956,6 +1960,9 @@ class FixedUpdatePatch case CustomRoles.Mastermind when !lowLoad: Mastermind.OnFixedUpdate(); break; + case CustomRoles.Magician when !lowLoad: + Magician.OnFixedUpdate(player); + break; case CustomRoles.SerialKiller: SerialKiller.FixedUpdate(player); break; diff --git a/Patches/ShipStatusPatch.cs b/Patches/ShipStatusPatch.cs index 981909990..6cd687ae9 100644 --- a/Patches/ShipStatusPatch.cs +++ b/Patches/ShipStatusPatch.cs @@ -102,6 +102,11 @@ class RepairSystemPatch Glitch.Mimic(player); return false; } + if (player.Is(CustomRoles.Magician)) + { + Magician.UseCard(player); + return false; + } if (player.Is(CustomRoleTypes.Impostor) && (player.IsAlive() || !Options.DeadImpCantSabotage.GetBool())) return true; if (player.Is(CustomRoles.Jackal) && Jackal.CanUseSabotage.GetBool()) return true; if (player.Is(CustomRoles.Sidekick) && Jackal.CanUseSabotageSK.GetBool()) return true; diff --git a/Resources/String.csv b/Resources/String.csv index 3ffb7b91c..0a857bacc 100644 --- a/Resources/String.csv +++ b/Resources/String.csv @@ -2669,6 +2669,45 @@ "MarkDone","","Position Marked","","","" "MarksCleared","","Marks cleared","","","" +"## Magician" +"Magician","","Magician","","","" +"MagicianInfo","","Play your cards to win","","","" +"MagicianInfoLong","","(Neutral):\nAs the Magician, you get a card after each kill you make. Whenever you get a card, a message will appear with its description and effect.\n\nTo play a card, call any sabotage (not doors) (the sabotage won't actually be called), or use the Pet button if the setting is on.","","","" +"MagicianSlownessValue","","Speed caused by Slowness Card","","","" +"MagicianSlownessRadius","","Slowness Card Radius","","","" +"MagicianSlownessDur","","Slowness Duration","","","" +"MagicianSpeedup","","Increased Speed","","","" +"MagicianSpeedupDur","","Increased Speed Duration","","","" +"MagicianLowKCD","","Kill Cooldown when using Overlocking Device","","","" +"MagicianBlindDur","","Blinding Card Duration","","","" +"MagicianBlindRadius","","Blinding Card Radius","","","" +"MagicianClearPortalAfterMeeting","","Clear Portals after meetings","","","" +"MagicianBombRadius","","Bomb Radius","","","" +"MagicianBombDelay","","Bomb Delay","","","" +"Magician-GetIdToName-1","","Slowness Potion","","","" +"Magician-GetIdToName-2","","Overclocking Device","","","" +"Magician-GetIdToName-3","","Teleporting Machine","","","" +"Magician-GetIdToName-4","","Portal Gun","","","" +"Magician-GetIdToName-5","","Sniper Rifle","","","" +"Magician-GetIdToName-6","","Flash Bomb","","","" +"Magician-GetIdToName-7","","Grenade","","","" +"Magician-GetIdToName-8","","Energy Drink","","","" +"Magician-GetIdToName-9","","Button Barry","","","" +"Magician-GetIdToName-10","","Admin Device","","","" +"Magician-GetIdToDesc-1","","Slows down everyone nearby for some time.","","","" +"Magician-GetIdToDesc-2","","Offsets your kill cooldown.","","","" +"Magician-GetIdToDesc-3","","Teleports you to a random vent.","","","" +"Magician-GetIdToDesc-4","","Use twice to mark 2 positions. Going near a marked position teleports you to the other.","","","" +"Magician-GetIdToDesc-5","","Sniper shot.","","","" +"Magician-GetIdToDesc-6","","Blinds everyone nearby for some time.","","","" +"Magician-GetIdToDesc-7","","Place a time bomb. When it explodes, it kills everyone nearby.","","","" +"Magician-GetIdToDesc-8","","Increases your speed for some time.","","","" +"Magician-GetIdToDesc-9","","Call a meeting.","","","" +"Magician-GetIdToDesc-10","","See how many players are in each room.","","","" +"MagicianBombExploded","","Time bomb exploded","","","" +"MagicianBombExlodesIn","","Bomb explodes in {0}s","","","" +"MagicianCardUsed","","Card used","","","" + "## Ignitor (Candle Lighter)" "Ignitor","","Ignitor","","","" "IgnitorInfo","","Light Candles for High Vision","","","" @@ -3336,6 +3375,9 @@ "WinnerRoleText.RuthlessRomantic","","Ruthless Romantic Wins!","","","" "WinnerRoleText.Eclipse","","Eclipse Wins!","","","" "WinnerRoleText.Pyromaniac","","Pyromaniac Wins!","","","" +"WinnerRoleText.Magician","","Magician Wins!","","","" +"WinnerRoleText.Reckless","","Reckless Wins!","","","" +"WinnerRoleText.Mafioso","","Mafioso Wins!","","","" "## Additional Winner Text" diff --git a/Roles/Crewmate/CameraMan.cs b/Roles/Crewmate/CameraMan.cs index 365e90207..63d9c9833 100644 --- a/Roles/Crewmate/CameraMan.cs +++ b/Roles/Crewmate/CameraMan.cs @@ -10,7 +10,7 @@ namespace TOHE.Roles.Crewmate public static class CameraMan { - private static readonly int Id = 640000; + private static readonly int Id = 641600; private static List playerIdList = new(); public static Dictionary UseLimit = new(); diff --git a/Roles/Crewmate/Farseer.cs b/Roles/Crewmate/Farseer.cs index b871b777a..5c8d4ba9a 100644 --- a/Roles/Crewmate/Farseer.cs +++ b/Roles/Crewmate/Farseer.cs @@ -158,10 +158,7 @@ namespace TOHE.Roles.Crewmate var rd = IRandom.Instance; var randomRole = randomRolesForTrickster[rd.Next(0, randomRolesForTrickster.Count)]; - string roleName = GetRoleName(randomRole); - string RoleText = ColorString(GetRoleColor(randomRole), GetString(randomRole.ToString())); - - return $"{RoleText}"; + return $"{ColorString(GetRoleColor(randomRole), GetString(randomRole.ToString()))}"; } public static string GetTaskState() diff --git a/Roles/Crewmate/Judge.cs b/Roles/Crewmate/Judge.cs index 3c6d1c508..d472a8a58 100644 --- a/Roles/Crewmate/Judge.cs +++ b/Roles/Crewmate/Judge.cs @@ -17,9 +17,9 @@ public static class Judge private static OptionItem TryHideMsg; private static OptionItem CanTrialMadmate; private static OptionItem CanTrialCharmed; - private static OptionItem CanTrialSidekick; - private static OptionItem CanTrialInfected; - private static OptionItem CanTrialContagious; + //private static OptionItem CanTrialSidekick; + //private static OptionItem CanTrialInfected; + //private static OptionItem CanTrialContagious; private static OptionItem CanTrialCrewKilling; private static OptionItem CanTrialNeutralB; private static OptionItem CanTrialNeutralK; @@ -34,9 +34,9 @@ public static class Judge .SetValueFormat(OptionFormat.Times); CanTrialMadmate = BooleanOptionItem.Create(Id + 12, "JudgeCanTrialMadmate", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); CanTrialCharmed = BooleanOptionItem.Create(Id + 16, "JudgeCanTrialCharmed", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialSidekick = BooleanOptionItem.Create(Id + 19, "JudgeCanTrialSidekick", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialInfected = BooleanOptionItem.Create(Id + 20, "JudgeCanTrialInfected", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); - CanTrialContagious = BooleanOptionItem.Create(Id + 21, "JudgeCanTrialContagious", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); + //CanTrialSidekick = BooleanOptionItem.Create(Id + 19, "JudgeCanTrialSidekick", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); + //CanTrialInfected = BooleanOptionItem.Create(Id + 20, "JudgeCanTrialInfected", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); + //CanTrialContagious = BooleanOptionItem.Create(Id + 21, "JudgeCanTrialContagious", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); CanTrialCrewKilling = BooleanOptionItem.Create(Id + 13, "JudgeCanTrialnCrewKilling", true, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); CanTrialNeutralB = BooleanOptionItem.Create(Id + 14, "JudgeCanTrialNeutralB", false, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); CanTrialNeutralE = BooleanOptionItem.Create(Id + 17, "JudgeCanTrialNeutralE", false, TabGroup.CrewmateRoles, false).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Judge]); diff --git a/Roles/Crewmate/Monarch.cs b/Roles/Crewmate/Monarch.cs index 4e7f2da7f..8a0a240bb 100644 --- a/Roles/Crewmate/Monarch.cs +++ b/Roles/Crewmate/Monarch.cs @@ -42,12 +42,12 @@ public static class Monarch } public static bool IsEnable => playerIdList.Any(); - private static void SendRPC() - { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetMonarchKnightLimit, SendOption.Reliable, -1); - writer.Write(KnightLimit); - AmongUsClient.Instance.FinishRpcImmediately(writer); - } + //private static void SendRPC() + //{ + // MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetMonarchKnightLimit, SendOption.Reliable, -1); + // writer.Write(KnightLimit); + // AmongUsClient.Instance.FinishRpcImmediately(writer); + //} public static void ReceiveRPC(MessageReader reader) { KnightLimit = reader.ReadInt32(); diff --git a/Roles/Neutral/Agitater.cs b/Roles/Neutral/Agitater.cs index 73ccf8f25..a5f417013 100644 --- a/Roles/Neutral/Agitater.cs +++ b/Roles/Neutral/Agitater.cs @@ -123,7 +123,7 @@ public static class Agitater Logger.Info($"{killer.GetRealName()} bombed {target.GetRealName()} on report", "Agitater"); } - public static void PassBomb(PlayerControl player, PlayerControl target, bool IsAgitater = false) + public static void PassBomb(PlayerControl player, PlayerControl target/*, bool IsAgitater = false*/) { if (!IsEnable) return; if (!AgitaterHasBombed) return; diff --git a/Roles/Neutral/Bandit.cs b/Roles/Neutral/Bandit.cs index 420559fac..0300cc85d 100644 --- a/Roles/Neutral/Bandit.cs +++ b/Roles/Neutral/Bandit.cs @@ -63,7 +63,7 @@ public static class Bandit } public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); - private static void SendRPC(byte playerId, bool isTargetList = false) + private static void SendRPC(byte playerId/*, bool isTargetList = false*/) { MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetBanditStealLimit, SendOption.Reliable, -1); writer.Write(playerId); diff --git a/Roles/Neutral/Infectious.cs b/Roles/Neutral/Infectious.cs index 763ed9093..40670d583 100644 --- a/Roles/Neutral/Infectious.cs +++ b/Roles/Neutral/Infectious.cs @@ -54,12 +54,12 @@ public static class Infectious Main.ResetCamPlayerList.Add(playerId); } public static bool IsEnable => playerIdList.Any(); - private static void SendRPC() - { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetInfectiousBiteLimit, SendOption.Reliable, -1); - writer.Write(BiteLimit); - AmongUsClient.Instance.FinishRpcImmediately(writer); - } + //private static void SendRPC() + //{ + // MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetInfectiousBiteLimit, SendOption.Reliable, -1); + // writer.Write(BiteLimit); + // AmongUsClient.Instance.FinishRpcImmediately(writer); + //} public static void ReceiveRPC(MessageReader reader) { BiteLimit = reader.ReadInt32(); diff --git a/Roles/Neutral/Mafioso.cs b/Roles/Neutral/Mafioso.cs index 12a825dfb..3287a9472 100644 --- a/Roles/Neutral/Mafioso.cs +++ b/Roles/Neutral/Mafioso.cs @@ -14,13 +14,15 @@ public static class Mafioso public static OptionItem CanVent; private static OptionItem HasImpostorVision; + public static bool CanKill = false; + public static void SetupCustomOption() { - SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.NSerialKiller, 1, zeroOne: false); - KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]) + SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Mafioso, 1, zeroOne: false); + KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Mafioso]) .SetValueFormat(OptionFormat.Seconds); - CanVent = BooleanOptionItem.Create(Id + 11, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]); - HasImpostorVision = BooleanOptionItem.Create(Id + 13, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]); + CanVent = BooleanOptionItem.Create(Id + 11, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Mafioso]); + HasImpostorVision = BooleanOptionItem.Create(Id + 13, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Mafioso]); } public static void Init() { @@ -37,10 +39,4 @@ public static class Mafioso public static bool IsEnable => playerIdList.Any(); public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); - public static void CanUseVent(PlayerControl player) - { - bool NSerialKiller_canUse = CanVent.GetBool(); - DestroyableSingleton.Instance.ImpostorVentButton.ToggleVisible(NSerialKiller_canUse && !player.Data.IsDead); - player.Data.Role.CanVent = NSerialKiller_canUse; - } } diff --git a/Roles/Neutral/Magician.cs b/Roles/Neutral/Magician.cs index cffc10acf..ffc3a4889 100644 --- a/Roles/Neutral/Magician.cs +++ b/Roles/Neutral/Magician.cs @@ -1,34 +1,98 @@ using AmongUs.GameOptions; using System.Collections.Generic; using System.Linq; +using System.Text; +using TOHE.Modules; +using TOHE.Roles.Crewmate; +using UnityEngine; using static TOHE.Options; +using static TOHE.Translator; +using static TOHE.Utils; namespace TOHE.Roles.Neutral; public static class Magician { - private static readonly int Id = 64300; + private static readonly int Id = 641300; public static List playerIdList = new(); private static OptionItem KillCooldown; public static OptionItem CanVent; private static OptionItem HasImpostorVision; + private static OptionItem Speed; + private static OptionItem SpeedDur; + private static OptionItem LowKCD; + private static OptionItem BlindDur; + private static OptionItem BlindRadius; + private static OptionItem SlownessRadius; + private static OptionItem SlownessDur; + private static OptionItem SlownessValue; + private static OptionItem BombRadius; + private static OptionItem BombDelay; + private static OptionItem ClearPortalAfterMeeting; + + private static byte CardId = byte.MaxValue; + + public static Dictionary SlowPPL = new(); + public static Dictionary TempSpeeds = new(); + public static Dictionary BlindPPL = new(); + public static Dictionary Bombs = new(); + private static List PortalMarks = new(); + private static bool isSniping = false; + private static byte snipeTarget = byte.MaxValue; + private static Vector3 snipeBasePosition; + private static bool isSpeedup = false; + private static float originalSpeed; + private static long lastTP = GetTimeStamp(); public static void SetupCustomOption() { - SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.NSerialKiller, 1, zeroOne: false); - KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]) + SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Magician, 1, zeroOne: false); + KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) .SetValueFormat(OptionFormat.Seconds); - CanVent = BooleanOptionItem.Create(Id + 11, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]); - HasImpostorVision = BooleanOptionItem.Create(Id + 13, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]); + + SlownessValue = FloatOptionItem.Create(Id + 11, "MagicianSlownessValue", new(0f, 1f, 0.05f), 1f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Multiplier); + SlownessRadius = FloatOptionItem.Create(Id + 12, "MagicianSlownessRadius", new(0f, 10f, 0.25f), 3f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Multiplier); + SlownessDur = IntegerOptionItem.Create(Id + 13, "MagicianSlownessDur", new(1, 30, 1), 10, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Seconds); + Speed = FloatOptionItem.Create(Id + 14, "MagicianSpeedup", new(0.1f, 3f, 0.05f), 1.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Multiplier); + SpeedDur = IntegerOptionItem.Create(Id + 15, "MagicianSpeedupDur", new(1, 20, 1), 10, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Seconds); + LowKCD = FloatOptionItem.Create(Id + 16, "MagicianLowKCD", new(1f, 20f, 1f), 5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Seconds); + BlindDur = IntegerOptionItem.Create(Id + 17, "MagicianBlindDur", new(1, 20, 1), 5, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Seconds); + BlindRadius = FloatOptionItem.Create(Id + 18, "MagicianBlindRadius", new(0f, 10f, 0.25f), 3f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Multiplier); + ClearPortalAfterMeeting = BooleanOptionItem.Create(Id + 19, "MagicianClearPortalAfterMeeting", false, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]); + BombRadius = FloatOptionItem.Create(Id + 20, "MagicianBombRadius", new(0f, 10f, 0.25f), 3f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Multiplier); + BombDelay = IntegerOptionItem.Create(Id + 21, "MagicianBombDelay", new(0, 10, 1), 3, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]) + .SetValueFormat(OptionFormat.Seconds); + + CanVent = BooleanOptionItem.Create(Id + 22, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]); + HasImpostorVision = BooleanOptionItem.Create(Id + 23, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Magician]); } public static void Init() { playerIdList = new(); + CardId = byte.MaxValue; + SlowPPL = new(); + BlindPPL = new(); + Bombs = new(); + PortalMarks = new(); + isSniping = false; + isSpeedup = false; + snipeTarget = byte.MaxValue; + lastTP = GetTimeStamp(); } public static void Add(byte playerId) { playerIdList.Add(playerId); + originalSpeed = Main.AllPlayerSpeed[playerId]; if (!AmongUsClient.Instance.AmHost) return; if (!Main.ResetCamPlayerList.Contains(playerId)) @@ -37,10 +101,296 @@ public static class Magician public static bool IsEnable => playerIdList.Any(); public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); - public static void CanUseVent(PlayerControl player) + public static void OnCheckMurder(PlayerControl killer) { - bool NSerialKiller_canUse = CanVent.GetBool(); - DestroyableSingleton.Instance.ImpostorVentButton.ToggleVisible(NSerialKiller_canUse && !player.Data.IsDead); - player.Data.Role.CanVent = NSerialKiller_canUse; + if (killer == null) return; + + CardId = (byte)IRandom.Instance.Next(1, 11); + + var sb = new StringBuilder(); + + sb.Append("\n\n"); + sb.AppendLine(ColorString(GetRoleColor(CustomRoles.Magician), $"Card name: {GetString($"Magician-GetIdToName-{CardId}")}")); + sb.AppendLine(ColorString(GetRoleColor(CustomRoles.Magician), $"Description: {GetString($"Magician-GetIdToDesc-{CardId}")}")); + sb.AppendLine(ColorString(GetRoleColor(CustomRoles.Magician), $"Trigger by: {(UsePets.GetBool() ? "Pet button" : "Sabotage")}")); + + killer.Notify(sb.ToString(), 15f); + } + public static void UseCard(PlayerControl pc) + { + if (pc == null) return; + if (CardId == byte.MaxValue) return; + + bool sync = false; + pc.Notify(GetString("MagicianCardUsed")); + + switch (CardId) + { + case 1: // Slowness for everyone nearby + if (TempSpeeds.Any()) RevertSpeedChanges(true); + var list = GetPlayersInRadius(SlownessRadius.GetFloat(), pc.transform.position); + for (int i = 0; i < list.Count; i++) + { + var x = list[i]; + if (x.PlayerId == pc.PlayerId || x == null) continue; + + TempSpeeds.TryAdd(x.PlayerId, Main.AllPlayerSpeed[x.PlayerId]); + SlowPPL.TryAdd(x.PlayerId, GetTimeStamp()); + Main.AllPlayerSpeed[x.PlayerId] = SlownessValue.GetFloat(); + x.MarkDirtySettings(); + } + CardId = byte.MaxValue; + break; + case 2: // Set KCD to x seconds + pc.SetKillCooldown(time: LowKCD.GetFloat()); + CardId = byte.MaxValue; + break; + case 3: // TP to nearest 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)); + CardId = byte.MaxValue; + break; + case 4: // Create Rift Maker portal + if (PortalMarks.Count == 2) PortalMarks.Clear(); + PortalMarks.Add(pc.transform.position); + if (PortalMarks.Count == 2) CardId = byte.MaxValue; + break; + case 5: // Snipe + var sniper = pc; + if (!isSniping) + { + snipeBasePosition = sniper.transform.position; + isSniping = true; + return; + } + + isSniping = false; + CardId = byte.MaxValue; + + if (!AmongUsClient.Instance.AmHost || Pelican.IsEaten(pc.PlayerId) || Medic.ProtectList.Contains(pc.PlayerId)) return; + sniper.RPCPlayCustomSound("AWP"); + + var targets = GetSnipeTargets(sniper); + + if (targets.Any()) + { + var snipedTarget = targets.OrderBy(c => c.Value).First().Key; + snipeTarget = snipedTarget.PlayerId; + snipedTarget.CheckMurder(snipedTarget); + var temp = sniper.killTimer; + sniper.SetKillCooldown(time: Main.AllPlayerKillCooldown[sniper.PlayerId] + temp); + snipeTarget = 0x7F; + + targets.Remove(snipedTarget); + var snList = new List(); + foreach (var otherPc in targets.Keys) + { + snList.Add(otherPc.PlayerId); + NotifyRoles(SpecifySeer: otherPc); + } + _ = new LateTask( + () => + { + snList.Clear(); + foreach (var otherPc in targets.Keys) + { + NotifyRoles(SpecifySeer: otherPc); + } + }, + 0.5f, "Sniper shot Notify" + ); + } + break; + case 6: // Blind everyone nearby + var players = GetPlayersInRadius(BlindRadius.GetFloat(), pc.transform.position); + for (int i = 0; i < players.Count; i++) + { + PlayerControl x = players[i]; + if (x.PlayerId == pc.PlayerId || x == null) continue; + + BlindPPL.TryAdd(x.PlayerId, GetTimeStamp()); + x.MarkDirtySettings(); + } + CardId = byte.MaxValue; + break; + case 7: // Time bomb: Place, explodes after x seconds, kills everyone nearby + Bombs.TryAdd(pc.transform.position, GetTimeStamp()); + CardId = byte.MaxValue; + break; + case 8: // Speed up + Main.AllPlayerSpeed[pc.PlayerId] = Speed.GetFloat(); + isSpeedup = true; + pc.MarkDirtySettings(); + _ = new LateTask(() => { Main.AllPlayerSpeed[pc.PlayerId] = originalSpeed; pc.MarkDirtySettings(); isSpeedup = false; }, SpeedDur.GetInt(), "Revert Magician Speed"); + CardId = byte.MaxValue; + break; + case 9: // Call meeting + pc.ReportDeadBody(null); + CardId = byte.MaxValue; + break; + case 10: // Admin map + NameNotifyManager.Notice.Remove(pc.PlayerId); + var rooms = ExtendedPlayerControl.GetAllPlayerLocationsCount(); + var sb = new StringBuilder(); + foreach (var location in rooms) + { + sb.Append($"\n{location.Key}: {location.Value}"); + } + pc.Notify(sb.ToString(), 10f); + break; + default: + break; + } + + if (sync) pc.SyncSettings(); + } + public static void OnFixedUpdate(PlayerControl pc) + { + if (pc == null) return; + if (pc.GetCustomRole() != CustomRoles.Magician) return; + if (!GameStates.IsInTask) return; + if (Pelican.IsEaten(pc.PlayerId) || pc.Data.IsDead) return; + + if (TempSpeeds.Any()) RevertSpeedChanges(false); + + if (PortalMarks.Count == 2 && lastTP + 5 < GetTimeStamp()) + { + if (Vector2.Distance(PortalMarks[0], PortalMarks[1]) <= 4f) + { + pc.Notify(GetString("IncorrectMarks")); + PortalMarks.Clear(); + } + else + { + Vector2 position = pc.transform.position; + + bool isTP = false; + Vector2 from = PortalMarks[0]; + + for (int i = 0; i < PortalMarks.Count; i++) + { + Vector2 mark = PortalMarks[i]; + var dis = Vector2.Distance(mark, position); + if (dis > 2f) continue; + + isTP = true; + from = mark; + } + + if (isTP) + { + lastTP = GetTimeStamp(); + if (from == PortalMarks[0]) + { + TP(pc.NetTransform, PortalMarks[1]); + } + else if (from == PortalMarks[1]) + { + TP(pc.NetTransform, PortalMarks[0]); + } + else + { + Logger.Error($"Teleport failed - from: {from}", "MagicianTP"); + } + } + } + } + + if (BlindPPL.Any()) + { + foreach (var x in BlindPPL.Where(x => x.Value + BlindDur.GetInt() < GetTimeStamp())) + { + BlindPPL.Remove(x.Key); + GetPlayerById(x.Key).MarkDirtySettings(); + } + } + + if (Bombs.Any()) + { + foreach (var bomb in Bombs.Where(bomb => bomb.Value + BombDelay.GetInt() < GetTimeStamp())) + { + bool b = false; + var players = GetPlayersInRadius(BombRadius.GetFloat(), bomb.Key); + for (int i = 0; i < players.Count; i++) + { + PlayerControl tg = players[i]; + if (tg.PlayerId == pc.PlayerId) + { + b = true; + continue; + } + Main.PlayerStates[tg.PlayerId].deathReason = PlayerState.DeathReason.Bombed; + tg.SetRealKiller(pc); + tg.RpcMurderPlayerV3(tg); + Medic.IsDead(tg); + } + Bombs.Remove(bomb.Key); + pc.Notify(GetString("MagicianBombExploded")); + if (b) _ = new LateTask(() => + { + if (!GameStates.IsEnded) + { + Main.PlayerStates[pc.PlayerId].deathReason = PlayerState.DeathReason.Bombed; + pc.RpcMurderPlayerV3(pc); + } + }, 0.5f, "Magician Bomb Suicide"); + } + + var sb = new StringBuilder(); + List list = Bombs.Values.ToList(); + for (int i = 0; i < list.Count; i++) + { + sb.Append(string.Format(GetString("MagicianBombExlodesIn"), BombDelay.GetInt() - (GetTimeStamp() - list[i]) + 1)); + } + pc.Notify(sb.ToString()); + } + } + public static void OnReportDeadBody() + { + SlowPPL.Clear(); + BlindPPL.Clear(); + Bombs.Clear(); + isSniping = false; + if (ClearPortalAfterMeeting.GetBool()) PortalMarks.Clear(); + if (isSpeedup) + { + isSpeedup = false; + Main.AllPlayerSpeed[playerIdList[0]] = originalSpeed; + } + } + private static void RevertSpeedChanges(bool force) + { + foreach (var x in TempSpeeds.Where(x => SlowPPL[x.Key] + SlownessDur.GetInt() < GetTimeStamp() || force)) + { + Main.AllPlayerSpeed[x.Key] = x.Value; + SlowPPL.Remove(x.Key); + TempSpeeds.Remove(x.Key); + GetPlayerById(x.Key).MarkDirtySettings(); + } + } + private static Dictionary GetSnipeTargets(PlayerControl sniper) + { + var targets = new Dictionary(); + var snipeBasePos = snipeBasePosition; + var snipePos = sniper.transform.position; + var dir = (snipePos - snipeBasePos).normalized; + + snipePos -= dir; + + foreach (var target in Main.AllAlivePlayerControls) + { + if (target.PlayerId == sniper.PlayerId) continue; + var target_pos = target.transform.position - snipePos; + if (target_pos.magnitude < 1) continue; + var target_dir = target_pos.normalized; + var target_dot = Vector3.Dot(dir, target_dir); + + if (target_dot < 0.995) continue; + + var err = target_pos.magnitude; + targets.Add(target, err); + } + return targets; } } diff --git a/Roles/Neutral/NSerialKiller.cs b/Roles/Neutral/NSerialKiller.cs index c86ea4916..71a8de65c 100644 --- a/Roles/Neutral/NSerialKiller.cs +++ b/Roles/Neutral/NSerialKiller.cs @@ -37,10 +37,4 @@ public static class NSerialKiller public static bool IsEnable => playerIdList.Any(); public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); - public static void CanUseVent(PlayerControl player) - { - bool NSerialKiller_canUse = CanVent.GetBool(); - DestroyableSingleton.Instance.ImpostorVentButton.ToggleVisible(NSerialKiller_canUse && !player.Data.IsDead); - player.Data.Role.CanVent = NSerialKiller_canUse; - } } diff --git a/Roles/Neutral/Postman.cs b/Roles/Neutral/Postman.cs index 1c284b223..6dfab5474 100644 --- a/Roles/Neutral/Postman.cs +++ b/Roles/Neutral/Postman.cs @@ -14,13 +14,15 @@ public static class Postman public static OptionItem CanVent; private static OptionItem HasImpostorVision; + public static bool IsFinished = false; + public static void SetupCustomOption() { - SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.NSerialKiller, 1, zeroOne: false); - KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]) + SetupSingleRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Postman, 1, zeroOne: false); + KillCooldown = FloatOptionItem.Create(Id + 10, "KillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Postman]) .SetValueFormat(OptionFormat.Seconds); - CanVent = BooleanOptionItem.Create(Id + 11, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]); - HasImpostorVision = BooleanOptionItem.Create(Id + 13, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.NSerialKiller]); + CanVent = BooleanOptionItem.Create(Id + 11, "CanVent", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Postman]); + HasImpostorVision = BooleanOptionItem.Create(Id + 13, "ImpostorVision", true, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Postman]); } public static void Init() { @@ -37,10 +39,4 @@ public static class Postman public static bool IsEnable => playerIdList.Any(); public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat(); public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); - public static void CanUseVent(PlayerControl player) - { - bool NSerialKiller_canUse = CanVent.GetBool(); - DestroyableSingleton.Instance.ImpostorVentButton.ToggleVisible(NSerialKiller_canUse && !player.Data.IsDead); - player.Data.Role.CanVent = NSerialKiller_canUse; - } } diff --git a/Roles/Neutral/Reckless.cs b/Roles/Neutral/Reckless.cs index 4bedd505f..6b263be20 100644 --- a/Roles/Neutral/Reckless.cs +++ b/Roles/Neutral/Reckless.cs @@ -1,3 +1,4 @@ +using AmongUs.GameOptions; using System; using System.Collections.Generic; using System.Linq; @@ -21,9 +22,9 @@ public static class Reckless public static void SetupCustomOption() { SetupRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Reckless); - DefaultKillCooldown = FloatOptionItem.Create(Id + 10, "SansDefaultKillCooldown", new(0f, 180f, 2.5f), 30f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Reckless]) + DefaultKillCooldown = FloatOptionItem.Create(Id + 10, "SansDefaultKillCooldown", new(0f, 180f, 2.5f), 22.5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Reckless]) .SetValueFormat(OptionFormat.Seconds); - ReduceKillCooldown = FloatOptionItem.Create(Id + 11, "SansReduceKillCooldown", new(0f, 30f, 0.5f), 4f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Reckless]) + ReduceKillCooldown = FloatOptionItem.Create(Id + 11, "SansReduceKillCooldown", new(0f, 30f, 0.5f), 5f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Reckless]) .SetValueFormat(OptionFormat.Seconds); MinKillCooldown = FloatOptionItem.Create(Id + 12, "SansMinKillCooldown", new(0f, 30f, 2.5f), 10f, TabGroup.NeutralRoles, false).SetParent(CustomRoleSpawnChances[CustomRoles.Reckless]) .SetValueFormat(OptionFormat.Seconds); @@ -46,6 +47,7 @@ public static class Reckless } public static bool IsEnable => playerIdList.Any(); public static void SetKillCooldown(byte id) => Main.AllPlayerKillCooldown[id] = NowCooldown[id]; + public static void ApplyGameOptions(IGameOptions opt) => opt.SetVision(HasImpostorVision.GetBool()); public static void OnCheckMurder(PlayerControl killer) { NowCooldown[killer.PlayerId] = Math.Clamp(NowCooldown[killer.PlayerId] - ReduceKillCooldown.GetFloat(), MinKillCooldown.GetFloat(), DefaultKillCooldown.GetFloat()); diff --git a/main.cs b/main.cs index 3f2c72bf6..b90105234 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.1.0"; - public const string PluginDisplayVersion = "1.1.0"; + public const string PluginVersion = "1.1.2"; + public const string PluginDisplayVersion = "1.1.2"; public const int PluginCreate = 3; public const bool Canary = false;