From f3480763162a34df80bfda48088bb1eafd157478 Mon Sep 17 00:00:00 2001 From: HyperAtill Date: Mon, 24 Nov 2025 18:16:35 +0300 Subject: [PATCH] nothing trust me --- CustomRoles.cs | 4 +- Main.cs | 2 +- Modules/CustomRolesHelper.cs | 14 +- Modules/ExtendedPlayerControl.cs | 2 +- Modules/GuessManager.cs | 2 +- Modules/OptionHolder.cs | 4 +- Modules/RPC.cs | 8 +- Modules/Utils.cs | 6 +- Patches/ChatCommandPatch.cs | 4 +- Patches/ExilePatch.cs | 2 +- Patches/HudPatch.cs | 2 +- Patches/IntroPatch.cs | 2 +- Patches/MeetingHudPatch.cs | 6 +- Patches/PlayerControlPatch.cs | 6 +- Patches/TaskAssignPatch.cs | 6 +- Resources/Lang/en_US.json | 22 +- Roles/Crewmate/CopyCat.cs | 2 +- Roles/Crewmate/MeetingManager.cs | 2 +- Roles/Crewmate/{NiceSwapper.cs => Swapper.cs} | 656 +++++++++--------- .../Impostor/{Capitalism.cs => Capitalist.cs} | 30 +- Roles/Impostor/Gangster.cs | 2 +- Roles/Neutral/Executioner.cs | 4 +- 22 files changed, 394 insertions(+), 394 deletions(-) rename Roles/Crewmate/{NiceSwapper.cs => Swapper.cs} (85%) rename Roles/Impostor/{Capitalism.cs => Capitalist.cs} (67%) diff --git a/CustomRoles.cs b/CustomRoles.cs index bad79da13..013df0587 100644 --- a/CustomRoles.cs +++ b/CustomRoles.cs @@ -32,7 +32,7 @@ public enum CustomRoles BountyHunter, Butcher, Camouflager, - Capitalism, + Capitalist, Cantankerous, Catalyst, Centralizer, @@ -234,7 +234,6 @@ public enum CustomRoles Mortician, NiceEraser, NiceGuesser, - NiceSwapper, Nightmare, Negotiator, Observer, @@ -266,6 +265,7 @@ public enum CustomRoles SpeedBooster, Spy, SuperStar, + Swapper, TaskManager, Telekinetic, Tether, diff --git a/Main.cs b/Main.cs index b101aadc8..57c06c7b5 100644 --- a/Main.cs +++ b/Main.cs @@ -503,7 +503,7 @@ public class Main : BasePlugin { CustomRoles.Deputy, "#df9026" }, { CustomRoles.Retributionist, "#cfc999" }, { CustomRoles.Cleanser, "#98FF98" }, - { CustomRoles.NiceSwapper, "#922348" }, + { CustomRoles.Swapper, "#922348" }, { CustomRoles.Ignitor, "#ffffa5" }, { CustomRoles.Guardian, "#2E8B57" }, { CustomRoles.Addict, "#008000" }, diff --git a/Modules/CustomRolesHelper.cs b/Modules/CustomRolesHelper.cs index e8c78171a..438e79e58 100644 --- a/Modules/CustomRolesHelper.cs +++ b/Modules/CustomRolesHelper.cs @@ -131,7 +131,7 @@ internal static class CustomRolesHelper CustomRoles.Terrorist => Terrorist.CanVent.GetBool() ? CustomRoles.Engineer : CustomRoles.Crewmate, CustomRoles.Executioner => CustomRoles.Crewmate, CustomRoles.Lawyer => CustomRoles.Crewmate, - CustomRoles.NiceSwapper => CustomRoles.Crewmate, + CustomRoles.Swapper => CustomRoles.Crewmate, CustomRoles.Ignitor => CustomRoles.Crewmate, CustomRoles.Jailor => UsePets && Jailor.UsePet.GetBool() ? CustomRoles.Crewmate : CustomRoles.Impostor, CustomRoles.Vampire => CustomRoles.Impostor, @@ -310,7 +310,7 @@ internal static class CustomRolesHelper CustomRoles.Scavenger => CustomRoles.Impostor, CustomRoles.Transporter => CustomRoles.Crewmate, CustomRoles.Veteran => UsePets ? CustomRoles.Crewmate : CustomRoles.Engineer, - CustomRoles.Capitalism => CustomRoles.Impostor, + CustomRoles.Capitalist => CustomRoles.Impostor, CustomRoles.Bodyguard => CustomRoles.Crewmate, CustomRoles.Grenadier => UsePets ? CustomRoles.Crewmate : CustomRoles.Engineer, CustomRoles.Lighter => UsePets ? CustomRoles.Crewmate : CustomRoles.Engineer, @@ -792,7 +792,7 @@ internal static class CustomRolesHelper CustomRoles.Nuker or CustomRoles.Scavenger or CustomRoles.Trapster or - CustomRoles.Capitalism or + CustomRoles.Capitalist or CustomRoles.Gangster or CustomRoles.Cleaner or CustomRoles.Lightning or @@ -1141,7 +1141,7 @@ internal static class CustomRolesHelper CustomRoles.Lazy when pc.Is(CustomRoles.LazyGuy) || pc.Is(CustomRoles.Snitch) || pc.Is(CustomRoles.Marshall) || pc.Is(CustomRoles.Transporter) || pc.Is(CustomRoles.Guardian) => false, CustomRoles.Tiebreaker when pc.Is(CustomRoles.Dictator) => false, CustomRoles.Stressed when !pc.IsCrewmate() || pc.GetCustomRole().IsTasklessCrewmate() => false, - CustomRoles.Stealer or CustomRoles.Swift or CustomRoles.DeadlyQuota or CustomRoles.Damocles or CustomRoles.Mare when pc.Is(CustomRoles.Bomber) || pc.Is(CustomRoles.Nuker) || pc.Is(CustomRoles.Trapster) || pc.Is(CustomRoles.Capitalism) => false, + CustomRoles.Stealer or CustomRoles.Swift or CustomRoles.DeadlyQuota or CustomRoles.Damocles or CustomRoles.Mare when pc.Is(CustomRoles.Bomber) || pc.Is(CustomRoles.Nuker) || pc.Is(CustomRoles.Trapster) || pc.Is(CustomRoles.Capitalist) => false, CustomRoles.Torch when !pc.IsCrewmate() || pc.Is(CustomRoles.Bewilder) || pc.Is(CustomRoles.Sunglasses) || pc.Is(CustomRoles.GuardianAngelEHR) => false, CustomRoles.Bewilder when pc.Is(CustomRoles.Torch) || pc.Is(CustomRoles.GuardianAngelEHR) || pc.Is(CustomRoles.Sunglasses) => false, CustomRoles.Dynamo when pc.Is(CustomRoles.Spurt) || pc.GetCustomRole() is CustomRoles.Tank or CustomRoles.Ankylosaurus => false, @@ -1424,7 +1424,7 @@ internal static class CustomRolesHelper public static bool IsDevFavoriteRole(this CustomRoles role) { - return role is CustomRoles.Adventurer or CustomRoles.Chef or CustomRoles.Detour or CustomRoles.Hacker or CustomRoles.NiceSwapper or CustomRoles.Sentinel or CustomRoles.Sentry or CustomRoles.Tornado or CustomRoles.Tunneler or CustomRoles.Whisperer or CustomRoles.Wizard or + return role is CustomRoles.Adventurer or CustomRoles.Chef or CustomRoles.Detour or CustomRoles.Hacker or CustomRoles.Swapper or CustomRoles.Sentinel or CustomRoles.Sentry or CustomRoles.Tornado or CustomRoles.Tunneler or CustomRoles.Whisperer or CustomRoles.Wizard or CustomRoles.Abyssbringer or CustomRoles.Assumer or CustomRoles.Chronomancer or CustomRoles.Echo or CustomRoles.Escapist or CustomRoles.Hypnotist or CustomRoles.Librarian or CustomRoles.Mafioso or CustomRoles.Mastermind or CustomRoles.Mercenary or CustomRoles.Penguin or CustomRoles.RiftMaker or CustomRoles.Sapper or CustomRoles.Wiper or CustomRoles.Bargainer or CustomRoles.Bubble or CustomRoles.Doomsayer or CustomRoles.Enderman or CustomRoles.Evolver or CustomRoles.HeadHunter or CustomRoles.Impartial or CustomRoles.Patroller or CustomRoles.Pawn or CustomRoles.Infection or CustomRoles.Postman or CustomRoles.Pyromaniac or CustomRoles.Revolutionist or CustomRoles.Rogue or CustomRoles.Romantic or CustomRoles.RoomRusher or CustomRoles.RouleteGrandeur or CustomRoles.Simon or CustomRoles.SoulHunter or CustomRoles.Sprayer or CustomRoles.Technician or CustomRoles.Tank or CustomRoles.Tiger or CustomRoles.Tremor or CustomRoles.Vengeance or CustomRoles.Vortex or CustomRoles.Werewolf or CustomRoles.WeaponMaster or CustomRoles.Reaper or CustomRoles.VoodooMaster or CustomRoles.Dreamweaver or CustomRoles.Banshee or @@ -1660,7 +1660,7 @@ internal static class CustomRolesHelper CustomRoles.Bard => RoleOptionType.Impostor_Support, CustomRoles.Blackmailer => RoleOptionType.Impostor_Support, CustomRoles.Camouflager => RoleOptionType.Impostor_Support, - CustomRoles.Capitalism => RoleOptionType.Impostor_Support, + CustomRoles.Capitalist => RoleOptionType.Impostor_Support, CustomRoles.Catalyst => RoleOptionType.Impostor_Support, CustomRoles.Centralizer => RoleOptionType.Impostor_Support, CustomRoles.Cleaner => RoleOptionType.Impostor_Support, @@ -1879,7 +1879,7 @@ internal static class CustomRolesHelper CustomRoles.Marshall => RoleOptionType.Crewmate_Power, CustomRoles.Mayor => RoleOptionType.Crewmate_Power, CustomRoles.NiceEraser => RoleOptionType.Crewmate_Power, - CustomRoles.NiceSwapper => RoleOptionType.Crewmate_Power, + CustomRoles.Swapper => RoleOptionType.Crewmate_Power, CustomRoles.Oxyman => RoleOptionType.Crewmate_Power, CustomRoles.President => RoleOptionType.Crewmate_Power, CustomRoles.Speedrunner => RoleOptionType.Crewmate_Power, diff --git a/Modules/ExtendedPlayerControl.cs b/Modules/ExtendedPlayerControl.cs index ef447f804..3cedbd29f 100644 --- a/Modules/ExtendedPlayerControl.cs +++ b/Modules/ExtendedPlayerControl.cs @@ -66,7 +66,7 @@ internal static class ExtendedPlayerControl public static bool UsesMeetingShapeshift(this PlayerControl player) { CustomRoles role = player.GetCustomRole(); - if (player.IsModdedClient() && role is CustomRoles.Judge or CustomRoles.NiceSwapper or CustomRoles.Nemesis) return false; + if (player.IsModdedClient() && role is CustomRoles.Judge or CustomRoles.Swapper or CustomRoles.Nemesis) return false; return role.UsesMeetingShapeshift(); } diff --git a/Modules/GuessManager.cs b/Modules/GuessManager.cs index c1044343a..031de687e 100644 --- a/Modules/GuessManager.cs +++ b/Modules/GuessManager.cs @@ -69,7 +69,7 @@ public static class GuessManager if (!AmongUsClient.Instance.AmHost) return false; if (!GameStates.IsMeeting || MeetingHud.Instance.state is MeetingHud.VoteStates.Results or MeetingHud.VoteStates.Proceeding || pc == null) return false; - bool hasGuessingRole = pc.GetCustomRole() is CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Doomsayer or CustomRoles.Judge or CustomRoles.NiceSwapper or CustomRoles.Councillor or CustomRoles.NecroGuesser or CustomRoles.Augur; + bool hasGuessingRole = pc.GetCustomRole() is CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Doomsayer or CustomRoles.Judge or CustomRoles.Swapper or CustomRoles.Councillor or CustomRoles.NecroGuesser or CustomRoles.Augur; if (!hasGuessingRole && !pc.Is(CustomRoles.Guesser) && !Options.GuesserMode.GetBool()) return false; int operate; // 1: ID, 2: Guess diff --git a/Modules/OptionHolder.cs b/Modules/OptionHolder.cs index 05a9a526b..2a5d9f395 100644 --- a/Modules/OptionHolder.cs +++ b/Modules/OptionHolder.cs @@ -390,8 +390,8 @@ public static class Options public static OptionItem GodfatherCancelVote; public static OptionItem GuardSpellTimes; - public static OptionItem CapitalismSkillCooldown; - public static OptionItem CapitalismKillCooldown; + public static OptionItem CapitalistSkillCooldown; + public static OptionItem CapitalistKillCooldown; public static OptionItem GrenadierSkillCooldown; public static OptionItem GrenadierSkillDuration; public static OptionItem GrenadierCauseVision; diff --git a/Modules/RPC.cs b/Modules/RPC.cs index 69018f124..571971709 100644 --- a/Modules/RPC.cs +++ b/Modules/RPC.cs @@ -123,7 +123,7 @@ public enum CustomRPC SetDoppelgangerStealLimit, SetJailorExeLimit, SetWwTimer, - SetNiceSwapperVotes, + SetSwapperVotes, Judge, Guess, MeetingKill, @@ -247,7 +247,7 @@ internal static class RPCHandlerPatch private static bool TrustedRpc(byte id) { if (SubmergedCompatibility.IsSubmerged() && id is >= 120 and <= 124) return true; - return (CustomRPC)id is CustomRPC.VersionCheck or CustomRPC.RequestRetryVersionCheck or CustomRPC.AntiBlackout or CustomRPC.SyncNameNotify or CustomRPC.RequestSendMessage or CustomRPC.RequestCommandProcessing or CustomRPC.Judge or CustomRPC.SetNiceSwapperVotes or CustomRPC.MeetingKill or CustomRPC.Guess or CustomRPC.NemesisRevenge or CustomRPC.BAU or CustomRPC.FFAKill or CustomRPC.TMGSync or CustomRPC.InspectorCommand or CustomRPC.ImitatorClick; + return (CustomRPC)id is CustomRPC.VersionCheck or CustomRPC.RequestRetryVersionCheck or CustomRPC.AntiBlackout or CustomRPC.SyncNameNotify or CustomRPC.RequestSendMessage or CustomRPC.RequestCommandProcessing or CustomRPC.Judge or CustomRPC.SetSwapperVotes or CustomRPC.MeetingKill or CustomRPC.Guess or CustomRPC.NemesisRevenge or CustomRPC.BAU or CustomRPC.FFAKill or CustomRPC.TMGSync or CustomRPC.InspectorCommand or CustomRPC.ImitatorClick; } private static bool CheckRateLimit(PlayerControl __instance, RpcCalls rpcType) @@ -1217,9 +1217,9 @@ internal static class RPCHandlerPatch } break; - case CustomRPC.SetNiceSwapperVotes: + case CustomRPC.SetSwapperVotes: { - NiceSwapper.ReceiveRPC(reader, __instance); + Swapper.ReceiveRPC(reader, __instance); break; } case CustomRPC.SetTrackerTarget: diff --git a/Modules/Utils.cs b/Modules/Utils.cs index a9cdb8989..a08254b29 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -1032,7 +1032,7 @@ public static class Utils (pc.Is(CustomRoles.Marshall) && !Options.MarshallCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Investigator) && !Options.InvestigatorCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.President) && !Options.PresidentCanBeMadmate.GetBool()) || - pc.Is(CustomRoles.NiceSwapper) || + pc.Is(CustomRoles.Swapper) || pc.Is(CustomRoles.Speedrunner) || pc.Is(CustomRoles.LazyGuy) || pc.Is(CustomRoles.Loyal) || @@ -3642,8 +3642,8 @@ public static class Utils } break; - case CustomRoles.NiceSwapper when disconnect: - NiceSwapper.SwapTargets = (byte.MaxValue, byte.MaxValue); + case CustomRoles.Swapper when disconnect: + Swapper.SwapTargets = (byte.MaxValue, byte.MaxValue); break; case CustomRoles.Silencer when disconnect: if (onMeeting) Main.Instance.StartCoroutine(CoRoutine()); diff --git a/Patches/ChatCommandPatch.cs b/Patches/ChatCommandPatch.cs index 8680b810c..540787249 100644 --- a/Patches/ChatCommandPatch.cs +++ b/Patches/ChatCommandPatch.cs @@ -391,7 +391,7 @@ internal static class ChatCommands { if (GuessManager.GuesserMsg(PlayerControl.LocalPlayer, text)) goto Canceled; if (Judge.TrialMsg(PlayerControl.LocalPlayer, text)) goto Canceled; - if (NiceSwapper.SwapMsg(PlayerControl.LocalPlayer, text)) goto Canceled; + if (Swapper.SwapMsg(PlayerControl.LocalPlayer, text)) goto Canceled; if (Inspector.InspectorCheckMsg(PlayerControl.LocalPlayer, text)) goto Canceled; if (Councillor.MurderMsg(PlayerControl.LocalPlayer, text)) goto Canceled; if (Medium.MsMsg(PlayerControl.LocalPlayer, text)) goto Canceled; @@ -3595,7 +3595,7 @@ internal static class ChatCommands { if (GuessManager.GuesserMsg(player, text) || Judge.TrialMsg(player, text) || - NiceSwapper.SwapMsg(player, text) || + Swapper.SwapMsg(player, text) || Inspector.InspectorCheckMsg(player, text) || Councillor.MurderMsg(player, text)) { diff --git a/Patches/ExilePatch.cs b/Patches/ExilePatch.cs index a12148230..10008bb05 100644 --- a/Patches/ExilePatch.cs +++ b/Patches/ExilePatch.cs @@ -78,7 +78,7 @@ internal static class ExileControllerWrapUpPatch Witch.RemoveSpelledPlayer(); - NiceSwapper.OnExileFinish(); + Swapper.OnExileFinish(); foreach (PlayerControl pc in Main.AllPlayerControls) { diff --git a/Patches/HudPatch.cs b/Patches/HudPatch.cs index dd05026b7..282fc914b 100644 --- a/Patches/HudPatch.cs +++ b/Patches/HudPatch.cs @@ -352,7 +352,7 @@ internal static class HudManagerPatch ActionButton button; Type type = state.Role.GetType(); - if (type.GetMethod("OnVote").DeclaringType == type || role is CustomRoles.Adrenaline or CustomRoles.Battery or CustomRoles.Dad or CustomRoles.Grappler or CustomRoles.Inquirer or CustomRoles.Judge or CustomRoles.Mechanic or CustomRoles.Medium or CustomRoles.NiceSwapper or CustomRoles.Inspector or CustomRoles.Spy or CustomRoles.Councillor or CustomRoles.CursedWolf or CustomRoles.Forger or CustomRoles.Generator or CustomRoles.Ventriloquist or CustomRoles.Bargainer or CustomRoles.Technician or CustomRoles.Virus) + if (type.GetMethod("OnVote").DeclaringType == type || role is CustomRoles.Adrenaline or CustomRoles.Battery or CustomRoles.Dad or CustomRoles.Grappler or CustomRoles.Inquirer or CustomRoles.Judge or CustomRoles.Mechanic or CustomRoles.Medium or CustomRoles.Swapper or CustomRoles.Inspector or CustomRoles.Spy or CustomRoles.Councillor or CustomRoles.CursedWolf or CustomRoles.Forger or CustomRoles.Generator or CustomRoles.Ventriloquist or CustomRoles.Bargainer or CustomRoles.Technician or CustomRoles.Virus) button = null; else if (role is CustomRoles.Coroner or CustomRoles.Occultist or CustomRoles.Vulture) button = __instance.ReportButton; diff --git a/Patches/IntroPatch.cs b/Patches/IntroPatch.cs index 76d455677..d8a6272e1 100644 --- a/Patches/IntroPatch.cs +++ b/Patches/IntroPatch.cs @@ -631,7 +631,7 @@ internal static class BeginCrewmatePatch CustomRoles.Dictator or CustomRoles.Mayor or - CustomRoles.NiceSwapper + CustomRoles.Swapper => HudManager.Instance.Chat.messageSound, CustomRoles.AntiAdminer or diff --git a/Patches/MeetingHudPatch.cs b/Patches/MeetingHudPatch.cs index a8a3be76d..4695aef6f 100644 --- a/Patches/MeetingHudPatch.cs +++ b/Patches/MeetingHudPatch.cs @@ -235,7 +235,7 @@ internal static class CheckForEndVotingPatch Dictionary votingData = __instance.CustomCalculateVotes(); Blackmailer.ManipulateVotingResult(votingData, states); - NiceSwapper.ManipulateVotingResult(votingData, states); + Swapper.ManipulateVotingResult(votingData, states); Assumer.OnVotingEnd(votingData); var exileId = byte.MaxValue; @@ -1123,7 +1123,7 @@ internal static class MeetingHudStartPatch GuessManager.StartMeetingPatch.Postfix(__instance); Inspector.StartMeetingPatch.Postfix(__instance); Judge.StartMeetingPatch.Postfix(__instance); - NiceSwapper.StartMeetingPatch.Postfix(__instance); + Swapper.StartMeetingPatch.Postfix(__instance); Councillor.StartMeetingPatch.Postfix(__instance); Nemesis.StartMeetingPatch.Postfix(__instance); Imitator.StartMeetingPatch.Postfix(__instance); @@ -1211,7 +1211,7 @@ internal static class MeetingHudUpdatePatch switch (myRole) { - case CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Judge or CustomRoles.NiceSwapper or CustomRoles.Councillor or CustomRoles.Guesser when !PlayerControl.LocalPlayer.IsAlive(): + case CustomRoles.NiceGuesser or CustomRoles.EvilGuesser or CustomRoles.Judge or CustomRoles.Swapper or CustomRoles.Councillor or CustomRoles.Guesser when !PlayerControl.LocalPlayer.IsAlive(): ClearShootButton(__instance, true); break; case CustomRoles.Nemesis when !PlayerControl.LocalPlayer.IsAlive() && GameObject.Find("ShootButton") == null: diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index c04bb4abf..265bb05e3 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -1034,9 +1034,9 @@ internal static class ReportDeadBodyPatch return false; } - if (__instance.Is(CustomRoles.NiceSwapper) && !NiceSwapper.CanStartMeeting.GetBool()) + if (__instance.Is(CustomRoles.Swapper) && !Swapper.CanStartMeeting.GetBool()) { - Notify("NiceSwapperCannotCallEmergencyMeeting"); + Notify("SwapperCannotCallEmergencyMeeting"); return false; } @@ -2234,7 +2234,7 @@ internal static class PlayerControlCompleteTaskPatch public static bool Prefix(PlayerControl __instance) { if (MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) return false; - return !Workhorse.OnCompleteTask(__instance) && Capitalism.AddTaskForPlayer(__instance); // Cancel task win + return !Workhorse.OnCompleteTask(__instance) && Capitalist.AddTaskForPlayer(__instance); // Cancel task win } public static void Postfix(PlayerControl __instance, [HarmonyArgument(0)] uint idx) diff --git a/Patches/TaskAssignPatch.cs b/Patches/TaskAssignPatch.cs index d26f18b50..e65c83b97 100644 --- a/Patches/TaskAssignPatch.cs +++ b/Patches/TaskAssignPatch.cs @@ -187,11 +187,11 @@ internal static class RpcSetTasksPatch // Workhorse task assignment if (pc.Is(CustomRoles.Workhorse)) (hasCommonTasks, numLongTasks, numShortTasks) = Workhorse.TaskData; - // Capitalism is going to harm people~ - if (Capitalism.CapitalismAssignTask.TryGetValue(pc.PlayerId, out int extraTasksNum)) + // Capitalist is going to harm people~ + if (Capitalist.CapitalistAssignTask.TryGetValue(pc.PlayerId, out int extraTasksNum)) { numShortTasks += extraTasksNum; - Capitalism.CapitalismAssignTask.Remove(pc.PlayerId); + Capitalist.CapitalistAssignTask.Remove(pc.PlayerId); } if (taskTypeIds.Length == 0) hasCommonTasks = false; // Set common to 0 when redistributing tasks diff --git a/Resources/Lang/en_US.json b/Resources/Lang/en_US.json index ab897f912..8554ce8d8 100644 --- a/Resources/Lang/en_US.json +++ b/Resources/Lang/en_US.json @@ -210,7 +210,7 @@ "Bomber": "Bomber", "Scavenger": "Scavenger", "Trapster": "Trapster", - "Capitalism": "Capitalist", + "Capitalist": "Capitalist", "Gangster": "Gangster", "Cleaner": "Cleaner", "Lightning": "Lightning", @@ -489,7 +489,7 @@ "TrapsterInfo": "Start a killing chain", "ScavengerInfo": "Your kills are unreportable", "EvilGuesserInfo": "Guess roles in meetings to kill", - "CapitalismInfo": "Give more tasks to crewmates", + "CapitalistInfo": "Give more tasks to crewmates", "GangsterInfo": "Convert players to your side", "CleanerInfo": "Report bodies to make them unreportable", "LightningInfo": "Convert players to Quantum Ghosts", @@ -719,7 +719,7 @@ "BomberInfoLong": "(Impostors):\\nThe Bomber can use the vanish/pet button to self-explode, killing players within a certain range. But as a price, the Bomber will also die. Note: All players will see a kill flash when the Bomber explodes.", "ScavengerInfoLong": "(Impostors):\\nScavenger kills do not leave dead bodies behind. To kill someone, you must click your kill button on them, then stay near that person for a few seconds, similar to an Arsonist douse.", "TrapsterInfoLong": "(Impostors):\\nAs the Trapster, you can vanish/pet to create a fake dead body. Anyone who reports this body will die, and depending on settings the body will be reported.\\n\\n(Legacy Version):\\nIn the game, the Trapster kills a player and then puts a trap on their body. If another player reports the dead body and it has the Trapster's trap on it, the player who reports will die instantly without the body getting reported. The player killed by the Trapster's trap will also become a Trapster. This chain reaction continues until no more players are left to become Trapsters. However, the Trapster will die immediately after making a kill. It's worth noting that the Trapster's own dead body cannot trigger their trap.", - "CapitalismInfoLong": "(Impostors):\\nCapitalists can add a short task to a player by pressing the kill button. Note: using this ability on players who have no tasks or have completed tasks will not take effect.", + "CapitalistInfoLong": "(Impostors):\\nCapitalists can add a short task to a player by pressing the kill button. Note: using this ability on players who have no tasks or have completed tasks will not take effect.", "GangsterInfoLong": "(Impostors):\\nThe Gangster can recruit a player to a Madmate by pressing the kill button. If successful, both will see the shield animation as a reminder. The host sets the maximum number of recruits. If recruitment fails, the target is killed normally. When out of recruits, the Gangster can only make normal kills.", "CleanerInfoLong": "(Impostors):\\nCleaner can press the Report button to clean up any dead body they come across.\\n\\nNote: You can only clean bodies if your kill cooldown is up.\\n\\nIf the cleanup is successful, the Cleaner will see a shield animation on their body as a reminder (only visible to himself). The cleaned up body cannot be reported (including Bait's).", "LightningInfoLong": "(Impostors):\\nThe Lightning role cannot make regular kills. When the Lightning uses its kill button, the target will vaporize into a quantum ghost. If a player who is not a quantum ghost touches the quantum ghost, the quantum ghost will die. If the quantum ghost survives until a meeting, they will die after the meeting ends. Interacting with the quantum ghost has no effect. Killing the Lightning may cause the killer to vaporize into a quantum ghost, depending on the host's settings.", @@ -1609,7 +1609,7 @@ "SnitchCanBeWorkhorse": "Snitch can become Workhorse", "WorkhorseSpawnChance": "Workhorse Spawn Chance", "InnocentCanWinByImp": "If their target was an Impostor then they win with them", - "CapitalismSkillCooldown": "Ability Cooldown", + "CapitalistSkillCooldown": "Ability Cooldown", "DualVotes": "Duplicate votes", "HideDualVotes": "Hide duplicated votes", "VeteranSkillCooldown": "Alert Cooldown", @@ -1845,7 +1845,7 @@ "CheckReportFail": "<#ff0000>This meeting call was canceled due to the following reason:\\n", "CannotCallEmergencyMeetingWhileSabotage": "Emergency meetings cannot be called during crisis", "JesterCannotCallEmergencyMeeting": "As the <#ec62a5>Jester, according to the host's settings, you cannot call emergency meetings", - "NiceSwapperCannotCallEmergencyMeeting": "As the <#922348>Nice Swapper, according to the host's settings, you cannot call emergency meetings", + "SwapperCannotCallEmergencyMeeting": "As the <#922348>Nice Swapper, according to the host's settings, you cannot call emergency meetings", "AdrenalineCannotCallEmergencyMeeting": "As the <#ffff00>Adrenaline, you cannot call emergency meetings currently", "PlayerWasRevived": "The player whose body you tried to report was revived", "HypnosisNoMeeting": "Everyone is in hypnosis, no meeting calls are allowed currently", @@ -3259,7 +3259,7 @@ "BountyHunterChangeButtonText": "Swap", "EvilTrackerChangeButtonText": "Track", "InnocentButtonText": "Frame", - "CapitalismButtonText": "Add Task", + "CapitalistButtonText": "Add Task", "PelicanButtonText": "Eat", "CounterfeiterButtonText": "Cheat", "PursuerButtonText": "Trick", @@ -4791,11 +4791,11 @@ "ExpressInfoLong": "(Crewmates):\\nAs the Express, you gain a small temporary speed boost after each task you complete.", "ExpressSpeed": "Increased Speed", "ExpressSpeedDur": "Increased Speed Duration", - "NiceSwapper": "Swapper", - "NiceSwapperInfo": "Swap players' votes", - "NiceSwapperInfoLong": "(Crewmates):\\nAs the Swapper, you can use the command /sw [ID] twice to choose 2 players. Those votes received by those 2 players will be swapped.\\nYou can see everyone's IDs next to their name.\\n\\nFor example, if 3 players voted red, and 5 players voted yellow, and you swap red and yellows' IDs, then red will receive 5 votes, and yellow will receive 3 votes.\\n\\nDue to technical difficulties, the Host's original vote will seem unchanged, but it's only visual, their vote will still get swapped.", - "NiceSwapperMax": "Initial Number of Swaps", - "NiceSwapperTrialMax": "Ability use limit reached", + "Swapper": "Swapper", + "SwapperInfo": "Swap players' votes", + "SwapperInfoLong": "(Crewmates):\\nAs the Swapper, you can use the command /sw [ID] twice to choose 2 players. Those votes received by those 2 players will be swapped.\\nYou can see everyone's IDs next to their name.\\n\\nFor example, if 3 players voted red, and 5 players voted yellow, and you swap red and yellows' IDs, then red will receive 5 votes, and yellow will receive 3 votes.\\n\\nDue to technical difficulties, the Host's original vote will seem unchanged, but it's only visual, their vote will still get swapped.", + "SwapperMax": "Initial Number of Swaps", + "SwapperTrialMax": "Ability use limit reached", "CanSwapSelfVotes": "Swapper Can Swap Themselves", "SwapperHideMsg": "Hide Swapper's commands", "CantSwapSelf": "You can't swap yourself", diff --git a/Roles/Crewmate/CopyCat.cs b/Roles/Crewmate/CopyCat.cs index 46dd7ec9b..d1546ae95 100644 --- a/Roles/Crewmate/CopyCat.cs +++ b/Roles/Crewmate/CopyCat.cs @@ -141,7 +141,7 @@ public class CopyCat : RoleBase CustomRoles.Demon => CustomRoles.Spy, CustomRoles.Undertaker or CustomRoles.Vortex => CustomRoles.Vacuum, CustomRoles.Kidnapper => CustomRoles.Autocrat, - CustomRoles.Capitalism => CustomRoles.Helper, + CustomRoles.Capitalist => CustomRoles.Helper, CustomRoles.Technician or CustomRoles.Saboteur => CustomRoles.Mechanic, CustomRoles.Inhibitor => new[] {CustomRoles.Doorjammer, CustomRoles.SecurityGuard}.RandomElement(), CustomRoles.Magician or CustomRoles.Curser => CustomRoles.Wizard, diff --git a/Roles/Crewmate/MeetingManager.cs b/Roles/Crewmate/MeetingManager.cs index 0866426d4..4817d2037 100644 --- a/Roles/Crewmate/MeetingManager.cs +++ b/Roles/Crewmate/MeetingManager.cs @@ -50,7 +50,7 @@ public class MeetingManager : RoleBase public static void OnSwap(PlayerControl tg1, PlayerControl tg2) { foreach (byte id in PlayerIdList) - LateTask.New(() => Utils.SendMessage(string.Format(GetString("MeetingManagerMessageAboutSwap"), CustomRoles.NiceSwapper.ToColoredString(), tg1.GetRealName().Replace("\n", " + "), tg2.GetRealName().Replace("\n", " + ")), id, Utils.ColorString(Utils.GetRoleColor(CustomRoles.MeetingManager), GetString("MeetingManagerMessageTitle"))), 1f, "Meeting Manager Messages"); + LateTask.New(() => Utils.SendMessage(string.Format(GetString("MeetingManagerMessageAboutSwap"), CustomRoles.Swapper.ToColoredString(), tg1.GetRealName().Replace("\n", " + "), tg2.GetRealName().Replace("\n", " + ")), id, Utils.ColorString(Utils.GetRoleColor(CustomRoles.MeetingManager), GetString("MeetingManagerMessageTitle"))), 1f, "Meeting Manager Messages"); } public static void OnCompare(PlayerControl tg1, PlayerControl tg2) diff --git a/Roles/Crewmate/NiceSwapper.cs b/Roles/Crewmate/Swapper.cs similarity index 85% rename from Roles/Crewmate/NiceSwapper.cs rename to Roles/Crewmate/Swapper.cs index 10aeb8e02..343d99272 100644 --- a/Roles/Crewmate/NiceSwapper.cs +++ b/Roles/Crewmate/Swapper.cs @@ -1,329 +1,329 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using EHR.Modules; -using EHR.Neutral; -using Hazel; -using UnityEngine; -using static EHR.Translator; - - -namespace EHR.Crewmate; - -public class NiceSwapper : RoleBase -{ - private const int Id = 642680; - - public static OptionItem SwapMax; - public static OptionItem HideMsg; - public static OptionItem CanSwapSelf; - public static OptionItem CanStartMeeting; - public static OptionItem NiceSwapperAbilityUseGainWithEachTaskCompleted; - public static OptionItem AbilityChargesWhenFinishedTasks; - - public static (byte, byte) SwapTargets = (byte.MaxValue, byte.MaxValue); - private static byte NiceSwapperId = byte.MaxValue; - - public override bool IsEnable => NiceSwapperId != byte.MaxValue; - public static bool On => NiceSwapperId != byte.MaxValue; - - public override void SetupCustomOption() - { - Options.SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.NiceSwapper); - - SwapMax = new IntegerOptionItem(Id + 3, "NiceSwapperMax", new(0, 20, 1), 1, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]) - .SetValueFormat(OptionFormat.Times); - - CanSwapSelf = new BooleanOptionItem(Id + 2, "CanSwapSelfVotes", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]); - CanStartMeeting = new BooleanOptionItem(Id + 4, "JesterCanUseButton", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]); - - NiceSwapperAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 6, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 0.3f, TabGroup.CrewmateRoles) - .SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]) - .SetValueFormat(OptionFormat.Times); - - AbilityChargesWhenFinishedTasks = new FloatOptionItem(Id + 7, "AbilityChargesWhenFinishedTasks", new(0f, 5f, 0.05f), 0.2f, TabGroup.CrewmateRoles) - .SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]) - .SetValueFormat(OptionFormat.Times); - - HideMsg = new BooleanOptionItem(Id + 5, "SwapperHideMsg", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.NiceSwapper]); - } - - public override void Init() - { - SwapTargets = (byte.MaxValue, byte.MaxValue); - NiceSwapperId = byte.MaxValue; - } - - public override void Add(byte playerId) - { - NiceSwapperId = playerId; - playerId.SetAbilityUseLimit(SwapMax.GetFloat()); - } - - public static bool SwapMsg(PlayerControl pc, string msg, bool isUI = false) - { - string originMsg = msg; - - if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || pc == null || pc.GetCustomRole() != CustomRoles.NiceSwapper) return false; - - Logger.Info($"{pc.GetNameWithRole()} : {msg} (UI: {isUI})", "Swapper"); - - int operate; - msg = msg.ToLower().TrimStart().TrimEnd(); - - if (CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id")) - operate = 1; - else if (CheckCommand(ref msg, "sw|换票|换|swap|st", false)) - operate = 2; - else - return false; - - switch (operate) - { - case 1: - Utils.SendMessage(GuessManager.GetFormatString(), pc.PlayerId); - break; - case 2: - { - if (!pc.IsAlive()) - { - if (!isUI) Utils.SendMessage(GetString("SwapDead"), pc.PlayerId, sendOption: SendOption.None); - pc.ShowPopUp(GetString("SwapDead")); - return true; - } - - if (pc.GetAbilityUseLimit() < 1) - { - if (!isUI) Utils.SendMessage(GetString("NiceSwapperTrialMax"), pc.PlayerId); - - pc.ShowPopUp(GetString("NiceSwapperTrialMax")); - return true; - } - - if (HideMsg.GetBool() && !isUI) - ChatManager.SendPreviousMessagesToAll(); - else if (pc.AmOwner && !isUI) Utils.SendMessage(originMsg, 255, pc.GetRealName()); - - if (!byte.TryParse(msg.Replace(" ", string.Empty), out byte targetId)) - { - Utils.SendMessage(GetString("SwapHelp"), pc.PlayerId); - return true; - } - - PlayerControl target = Utils.GetPlayerById(targetId); - if (target == null) break; - - bool targetIsntSelected = SwapTargets.Item1 != target.PlayerId && SwapTargets.Item2 != target.PlayerId; // Whether the picked target isn't already being swapped - - bool vote1Empty = SwapTargets.Item1 == byte.MaxValue && targetIsntSelected; // Whether the first swapping slot is suitable to swap this target - bool vote2Available = SwapTargets.Item1 != byte.MaxValue && SwapTargets.Item2 == byte.MaxValue && targetIsntSelected; // Whether the second swapping slot is suitable to swap this target - bool selfCheck = CanSwapSelf.GetBool() || target.PlayerId != pc.PlayerId; - - if (vote1Empty && selfCheck) // Take the first slot - { - SwapTargets.Item1 = target.PlayerId; - - if (!isUI) Utils.SendMessage(GetString("Swap1"), pc.PlayerId); - - Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} chose to swap {target.GetNameWithRole()} (first target)", "Swapper"); - } - - else if (vote2Available && selfCheck) // Take the second slot - { - SwapTargets.Item2 = target.PlayerId; - - if (!isUI) Utils.SendMessage(GetString("Swap2"), pc.PlayerId); - - Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} chose to swap {target.GetNameWithRole()} (second target)", "Swapper"); - } - - else if (target.PlayerId == SwapTargets.Item1) // If this player is already chosen to be swapped in the first slot, cancel it - { - SwapTargets.Item1 = byte.MaxValue; - - if (!isUI) Utils.SendMessage(GetString("CancelSwap1"), pc.PlayerId); - - Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} canceled swapping on {target.GetNameWithRole()} (first target)", "Swapper"); - } - - else if (target.PlayerId == SwapTargets.Item2) // If this player is already chosen to be swapped in the second slot, cancel it - { - SwapTargets.Item2 = byte.MaxValue; - - if (!isUI) Utils.SendMessage(GetString("CancelSwap2"), pc.PlayerId); - - Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} canceled swapping on {target.GetNameWithRole()} (second target)", "Swapper"); - } - - else if (!selfCheck) // When the Swapper tries to swap themselves, but they aren't allowed to - { - if (!isUI) - Utils.SendMessage(GetString("CantSwapSelf"), pc.PlayerId); - else - pc.ShowPopUp(GetString("CantSwapSelf")); - } - - - if (CustomRoles.MeetingManager.RoleExist()) - { - PlayerControl pc1 = SwapTargets.Item1.GetPlayer(); - PlayerControl pc2 = SwapTargets.Item2.GetPlayer(); - - if (pc1 != null && pc2 != null) - MeetingManager.OnSwap(pc1, pc2); - } - - break; - } - } - - return true; - } - - public static void OnExileFinish() - { - if (SwapTargets != (byte.MaxValue, byte.MaxValue)) - { - Utils.GetPlayerById(NiceSwapperId).RpcRemoveAbilityUse(); - SwapTargets = (byte.MaxValue, byte.MaxValue); - } - } - - public static void ManipulateVotingResult(Dictionary votingData, MeetingHud.VoterState[] states) - { - try - { - if (NiceSwapperId == byte.MaxValue || SwapTargets.Item1 == byte.MaxValue || SwapTargets.Item2 == byte.MaxValue) return; - - // Swap the number of votes received internally - int count1 = votingData.GetValueOrDefault(SwapTargets.Item1, 0); - int count2 = votingData.GetValueOrDefault(SwapTargets.Item2, 0); - votingData[SwapTargets.Item1] = count2; - votingData[SwapTargets.Item2] = count1; - - // Swap the votes visually - List votedFor1 = states.Where(x => x.VotedForId == SwapTargets.Item1).Select(x => x.VoterId).ToList(); - List votedFor2 = states.Where(x => x.VotedForId == SwapTargets.Item2).Select(x => x.VoterId).ToList(); - - for (var index = 0; index < states.Length; index++) - { - ref MeetingHud.VoterState state = ref states[index]; - - if (votedFor1.Contains(state.VoterId)) - state.VotedForId = SwapTargets.Item2; - else if (votedFor2.Contains(state.VoterId)) - state.VotedForId = SwapTargets.Item1; - } - - Utils.SendMessage(string.Format(GetString("SwapVote"), SwapTargets.Item1.ColoredPlayerName(), SwapTargets.Item2.ColoredPlayerName()), title: Utils.ColorString(Utils.GetRoleColor(CustomRoles.NiceSwapper), GetString("SwapTitle"))); - } - catch (Exception e) { Utils.ThrowException(e); } - } - - private static bool CheckCommand(ref string msg, string command, bool exact = true) - { - string[] comList = command.Split('|'); - - foreach (string str in comList) - { - if (exact) - { - if (msg == "/" + str) return true; - } - else - { - if (msg.StartsWith("/" + str)) - { - msg = msg.Replace("/" + str, string.Empty); - return true; - } - } - } - - return false; - } - - public override void OnMeetingShapeshift(PlayerControl shapeshifter, PlayerControl target) - { - if (Starspawn.IsDayBreak) return; - SwapMsg(shapeshifter, $"/sw {target.PlayerId}"); - } - - private static void SendRPC(byte playerId) - { - MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetNiceSwapperVotes, SendOption.Reliable, AmongUsClient.Instance.HostId); - writer.Write(playerId); - AmongUsClient.Instance.FinishRpcImmediately(writer); - } - - public static void ReceiveRPC(MessageReader reader, PlayerControl pc) - { - byte playerId = reader.ReadByte(); - SwapMsg(pc, $"/sw {playerId}", true); - } - - private static void SwapperOnClick(byte playerId, MeetingHud __instance) - { - Logger.Msg($"Click: ID {playerId}", "NiceSwapper UI"); - - PlayerControl pc = Utils.GetPlayerById(playerId); - if (pc == null || !pc.IsAlive() || !GameStates.IsVoting) return; - - if (AmongUsClient.Instance.AmHost) - SwapMsg(PlayerControl.LocalPlayer, $"/sw {playerId}", true); - else - SendRPC(playerId); - - if (PlayerControl.LocalPlayer.GetCustomRole() == CustomRoles.NiceSwapper && PlayerControl.LocalPlayer.IsAlive()) - { - __instance.playerStates.ToList().ForEach(x => - { - Transform swapButton = x.transform.FindChild("ShootButton"); - if (swapButton != null) Object.Destroy(swapButton.gameObject); - }); - - CreateSwapperButton(__instance); - } - } - - private static void CreateSwapperButton(MeetingHud __instance) - { - foreach (PlayerVoteArea pva in __instance.playerStates) - { - PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); - if (pc == null || !pc.IsAlive()) continue; - - GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; - GameObject targetBox = Object.Instantiate(template, pva.transform); - targetBox.name = "ShootButton"; - targetBox.transform.localPosition = new(-0.35f, 0.03f, -1.31f); - var renderer = targetBox.GetComponent(); - - if (pc.PlayerId == pva.TargetPlayerId && (SwapTargets.Item1 == pc.PlayerId || SwapTargets.Item2 == pc.PlayerId)) - renderer.sprite = CustomButton.Get("SwapYes"); - else - renderer.sprite = CustomButton.Get("SwapNo"); - - var button = targetBox.GetComponent(); - button.OnClick.RemoveAllListeners(); - button.OnClick.AddListener((Action)(() => SwapperOnClick(pva.TargetPlayerId, __instance))); - } - } - - //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] - public static class StartMeetingPatch - { - // ReSharper disable once UnusedMember.Local - public static void Postfix(MeetingHud __instance) - { - if (PlayerControl.LocalPlayer.GetCustomRole() == CustomRoles.NiceSwapper && PlayerControl.LocalPlayer.IsAlive()) - CreateSwapperButton(__instance); - } - } - - public override void ManipulateGameEndCheckCrew(out bool keepGameGoing, out int countsAs) - { - keepGameGoing = true; - countsAs = 1; - } +using System; +using System.Collections.Generic; +using System.Linq; +using EHR.Modules; +using EHR.Neutral; +using Hazel; +using UnityEngine; +using static EHR.Translator; + + +namespace EHR.Crewmate; + +public class Swapper : RoleBase +{ + private const int Id = 642680; + + public static OptionItem SwapMax; + public static OptionItem HideMsg; + public static OptionItem CanSwapSelf; + public static OptionItem CanStartMeeting; + public static OptionItem SwapperAbilityUseGainWithEachTaskCompleted; + public static OptionItem AbilityChargesWhenFinishedTasks; + + public static (byte, byte) SwapTargets = (byte.MaxValue, byte.MaxValue); + private static byte SwapperId = byte.MaxValue; + + public override bool IsEnable => SwapperId != byte.MaxValue; + public static bool On => SwapperId != byte.MaxValue; + + public override void SetupCustomOption() + { + Options.SetupSingleRoleOptions(Id, TabGroup.CrewmateRoles, CustomRoles.Swapper); + + SwapMax = new IntegerOptionItem(Id + 3, "SwapperMax", new(0, 20, 1), 1, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Swapper]) + .SetValueFormat(OptionFormat.Times); + + CanSwapSelf = new BooleanOptionItem(Id + 2, "CanSwapSelfVotes", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Swapper]); + CanStartMeeting = new BooleanOptionItem(Id + 4, "JesterCanUseButton", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Swapper]); + + SwapperAbilityUseGainWithEachTaskCompleted = new FloatOptionItem(Id + 6, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 0.3f, TabGroup.CrewmateRoles) + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Swapper]) + .SetValueFormat(OptionFormat.Times); + + AbilityChargesWhenFinishedTasks = new FloatOptionItem(Id + 7, "AbilityChargesWhenFinishedTasks", new(0f, 5f, 0.05f), 0.2f, TabGroup.CrewmateRoles) + .SetParent(Options.CustomRoleSpawnChances[CustomRoles.Swapper]) + .SetValueFormat(OptionFormat.Times); + + HideMsg = new BooleanOptionItem(Id + 5, "SwapperHideMsg", true, TabGroup.CrewmateRoles).SetParent(Options.CustomRoleSpawnChances[CustomRoles.Swapper]); + } + + public override void Init() + { + SwapTargets = (byte.MaxValue, byte.MaxValue); + SwapperId = byte.MaxValue; + } + + public override void Add(byte playerId) + { + SwapperId = playerId; + playerId.SetAbilityUseLimit(SwapMax.GetFloat()); + } + + public static bool SwapMsg(PlayerControl pc, string msg, bool isUI = false) + { + string originMsg = msg; + + if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || pc == null || pc.GetCustomRole() != CustomRoles.Swapper) return false; + + Logger.Info($"{pc.GetNameWithRole()} : {msg} (UI: {isUI})", "Swapper"); + + int operate; + msg = msg.ToLower().TrimStart().TrimEnd(); + + if (CheckCommand(ref msg, "id|guesslist|gl编号|玩家编号|玩家id|id列表|玩家列表|列表|所有id|全部id")) + operate = 1; + else if (CheckCommand(ref msg, "sw|换票|换|swap|st", false)) + operate = 2; + else + return false; + + switch (operate) + { + case 1: + Utils.SendMessage(GuessManager.GetFormatString(), pc.PlayerId); + break; + case 2: + { + if (!pc.IsAlive()) + { + if (!isUI) Utils.SendMessage(GetString("SwapDead"), pc.PlayerId, sendOption: SendOption.None); + pc.ShowPopUp(GetString("SwapDead")); + return true; + } + + if (pc.GetAbilityUseLimit() < 1) + { + if (!isUI) Utils.SendMessage(GetString("SwapperTrialMax"), pc.PlayerId); + + pc.ShowPopUp(GetString("SwapperTrialMax")); + return true; + } + + if (HideMsg.GetBool() && !isUI) + ChatManager.SendPreviousMessagesToAll(); + else if (pc.AmOwner && !isUI) Utils.SendMessage(originMsg, 255, pc.GetRealName()); + + if (!byte.TryParse(msg.Replace(" ", string.Empty), out byte targetId)) + { + Utils.SendMessage(GetString("SwapHelp"), pc.PlayerId); + return true; + } + + PlayerControl target = Utils.GetPlayerById(targetId); + if (target == null) break; + + bool targetIsntSelected = SwapTargets.Item1 != target.PlayerId && SwapTargets.Item2 != target.PlayerId; // Whether the picked target isn't already being swapped + + bool vote1Empty = SwapTargets.Item1 == byte.MaxValue && targetIsntSelected; // Whether the first swapping slot is suitable to swap this target + bool vote2Available = SwapTargets.Item1 != byte.MaxValue && SwapTargets.Item2 == byte.MaxValue && targetIsntSelected; // Whether the second swapping slot is suitable to swap this target + bool selfCheck = CanSwapSelf.GetBool() || target.PlayerId != pc.PlayerId; + + if (vote1Empty && selfCheck) // Take the first slot + { + SwapTargets.Item1 = target.PlayerId; + + if (!isUI) Utils.SendMessage(GetString("Swap1"), pc.PlayerId); + + Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} chose to swap {target.GetNameWithRole()} (first target)", "Swapper"); + } + + else if (vote2Available && selfCheck) // Take the second slot + { + SwapTargets.Item2 = target.PlayerId; + + if (!isUI) Utils.SendMessage(GetString("Swap2"), pc.PlayerId); + + Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} chose to swap {target.GetNameWithRole()} (second target)", "Swapper"); + } + + else if (target.PlayerId == SwapTargets.Item1) // If this player is already chosen to be swapped in the first slot, cancel it + { + SwapTargets.Item1 = byte.MaxValue; + + if (!isUI) Utils.SendMessage(GetString("CancelSwap1"), pc.PlayerId); + + Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} canceled swapping on {target.GetNameWithRole()} (first target)", "Swapper"); + } + + else if (target.PlayerId == SwapTargets.Item2) // If this player is already chosen to be swapped in the second slot, cancel it + { + SwapTargets.Item2 = byte.MaxValue; + + if (!isUI) Utils.SendMessage(GetString("CancelSwap2"), pc.PlayerId); + + Logger.Info($"{pc.GetNameWithRole().RemoveHtmlTags()} canceled swapping on {target.GetNameWithRole()} (second target)", "Swapper"); + } + + else if (!selfCheck) // When the Swapper tries to swap themselves, but they aren't allowed to + { + if (!isUI) + Utils.SendMessage(GetString("CantSwapSelf"), pc.PlayerId); + else + pc.ShowPopUp(GetString("CantSwapSelf")); + } + + + if (CustomRoles.MeetingManager.RoleExist()) + { + PlayerControl pc1 = SwapTargets.Item1.GetPlayer(); + PlayerControl pc2 = SwapTargets.Item2.GetPlayer(); + + if (pc1 != null && pc2 != null) + MeetingManager.OnSwap(pc1, pc2); + } + + break; + } + } + + return true; + } + + public static void OnExileFinish() + { + if (SwapTargets != (byte.MaxValue, byte.MaxValue)) + { + Utils.GetPlayerById(SwapperId).RpcRemoveAbilityUse(); + SwapTargets = (byte.MaxValue, byte.MaxValue); + } + } + + public static void ManipulateVotingResult(Dictionary votingData, MeetingHud.VoterState[] states) + { + try + { + if (SwapperId == byte.MaxValue || SwapTargets.Item1 == byte.MaxValue || SwapTargets.Item2 == byte.MaxValue) return; + + // Swap the number of votes received internally + int count1 = votingData.GetValueOrDefault(SwapTargets.Item1, 0); + int count2 = votingData.GetValueOrDefault(SwapTargets.Item2, 0); + votingData[SwapTargets.Item1] = count2; + votingData[SwapTargets.Item2] = count1; + + // Swap the votes visually + List votedFor1 = states.Where(x => x.VotedForId == SwapTargets.Item1).Select(x => x.VoterId).ToList(); + List votedFor2 = states.Where(x => x.VotedForId == SwapTargets.Item2).Select(x => x.VoterId).ToList(); + + for (var index = 0; index < states.Length; index++) + { + ref MeetingHud.VoterState state = ref states[index]; + + if (votedFor1.Contains(state.VoterId)) + state.VotedForId = SwapTargets.Item2; + else if (votedFor2.Contains(state.VoterId)) + state.VotedForId = SwapTargets.Item1; + } + + Utils.SendMessage(string.Format(GetString("SwapVote"), SwapTargets.Item1.ColoredPlayerName(), SwapTargets.Item2.ColoredPlayerName()), title: Utils.ColorString(Utils.GetRoleColor(CustomRoles.Swapper), GetString("SwapTitle"))); + } + catch (Exception e) { Utils.ThrowException(e); } + } + + private static bool CheckCommand(ref string msg, string command, bool exact = true) + { + string[] comList = command.Split('|'); + + foreach (string str in comList) + { + if (exact) + { + if (msg == "/" + str) return true; + } + else + { + if (msg.StartsWith("/" + str)) + { + msg = msg.Replace("/" + str, string.Empty); + return true; + } + } + } + + return false; + } + + public override void OnMeetingShapeshift(PlayerControl shapeshifter, PlayerControl target) + { + if (Starspawn.IsDayBreak) return; + SwapMsg(shapeshifter, $"/sw {target.PlayerId}"); + } + + private static void SendRPC(byte playerId) + { + MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetSwapperVotes, SendOption.Reliable, AmongUsClient.Instance.HostId); + writer.Write(playerId); + AmongUsClient.Instance.FinishRpcImmediately(writer); + } + + public static void ReceiveRPC(MessageReader reader, PlayerControl pc) + { + byte playerId = reader.ReadByte(); + SwapMsg(pc, $"/sw {playerId}", true); + } + + private static void SwapperOnClick(byte playerId, MeetingHud __instance) + { + Logger.Msg($"Click: ID {playerId}", "Swapper UI"); + + PlayerControl pc = Utils.GetPlayerById(playerId); + if (pc == null || !pc.IsAlive() || !GameStates.IsVoting) return; + + if (AmongUsClient.Instance.AmHost) + SwapMsg(PlayerControl.LocalPlayer, $"/sw {playerId}", true); + else + SendRPC(playerId); + + if (PlayerControl.LocalPlayer.GetCustomRole() == CustomRoles.Swapper && PlayerControl.LocalPlayer.IsAlive()) + { + __instance.playerStates.ToList().ForEach(x => + { + Transform swapButton = x.transform.FindChild("ShootButton"); + if (swapButton != null) Object.Destroy(swapButton.gameObject); + }); + + CreateSwapperButton(__instance); + } + } + + private static void CreateSwapperButton(MeetingHud __instance) + { + foreach (PlayerVoteArea pva in __instance.playerStates) + { + PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId); + if (pc == null || !pc.IsAlive()) continue; + + GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject; + GameObject targetBox = Object.Instantiate(template, pva.transform); + targetBox.name = "ShootButton"; + targetBox.transform.localPosition = new(-0.35f, 0.03f, -1.31f); + var renderer = targetBox.GetComponent(); + + if (pc.PlayerId == pva.TargetPlayerId && (SwapTargets.Item1 == pc.PlayerId || SwapTargets.Item2 == pc.PlayerId)) + renderer.sprite = CustomButton.Get("SwapYes"); + else + renderer.sprite = CustomButton.Get("SwapNo"); + + var button = targetBox.GetComponent(); + button.OnClick.RemoveAllListeners(); + button.OnClick.AddListener((Action)(() => SwapperOnClick(pva.TargetPlayerId, __instance))); + } + } + + //[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.Start))] + public static class StartMeetingPatch + { + // ReSharper disable once UnusedMember.Local + public static void Postfix(MeetingHud __instance) + { + if (PlayerControl.LocalPlayer.GetCustomRole() == CustomRoles.Swapper && PlayerControl.LocalPlayer.IsAlive()) + CreateSwapperButton(__instance); + } + } + + public override void ManipulateGameEndCheckCrew(out bool keepGameGoing, out int countsAs) + { + keepGameGoing = true; + countsAs = 1; + } } \ No newline at end of file diff --git a/Roles/Impostor/Capitalism.cs b/Roles/Impostor/Capitalist.cs similarity index 67% rename from Roles/Impostor/Capitalism.cs rename to Roles/Impostor/Capitalist.cs index d3541d2c5..ab63ddd6a 100644 --- a/Roles/Impostor/Capitalism.cs +++ b/Roles/Impostor/Capitalist.cs @@ -3,19 +3,19 @@ using static EHR.Options; namespace EHR.Impostor; -internal class Capitalism : RoleBase +internal class Capitalist : RoleBase { - private static readonly Dictionary CapitalismAddTask = []; - public static readonly Dictionary CapitalismAssignTask = []; + private static readonly Dictionary CapitalistAddTask = []; + public static readonly Dictionary CapitalistAssignTask = []; public static bool On; public override bool IsEnable => On; public override void SetupCustomOption() { - SetupRoleOptions(16600, TabGroup.ImpostorRoles, CustomRoles.Capitalism); + SetupRoleOptions(16600, TabGroup.ImpostorRoles, CustomRoles.Capitalist); - CapitalismKillCooldown = new FloatOptionItem(16611, "KillCooldown", new(2.5f, 60f, 0.5f), 25f, TabGroup.ImpostorRoles) - .SetParent(CustomRoleSpawnChances[CustomRoles.Capitalism]) + CapitalistKillCooldown = new FloatOptionItem(16611, "KillCooldown", new(2.5f, 60f, 0.5f), 25f, TabGroup.ImpostorRoles) + .SetParent(CustomRoleSpawnChances[CustomRoles.Capitalist]) .SetValueFormat(OptionFormat.Seconds); } @@ -31,33 +31,33 @@ internal class Capitalism : RoleBase public override void SetButtonTexts(HudManager hud, byte id) { - hud.KillButton?.OverrideText(Translator.GetString("CapitalismButtonText")); + hud.KillButton?.OverrideText(Translator.GetString("CapitalistButtonText")); } public override void SetKillCooldown(byte id) { - Main.AllPlayerKillCooldown[id] = CapitalismKillCooldown.GetFloat(); + Main.AllPlayerKillCooldown[id] = CapitalistKillCooldown.GetFloat(); } public override bool OnCheckMurder(PlayerControl killer, PlayerControl target) { return killer.CheckDoubleTrigger(target, () => { - CapitalismAddTask.TryAdd(target.PlayerId, 0); - CapitalismAddTask[target.PlayerId]++; - CapitalismAssignTask.TryAdd(target.PlayerId, 0); - CapitalismAssignTask[target.PlayerId]++; - Logger.Info($"{killer.GetRealName()} added a task for: {target.GetRealName()}", "Capitalism Add Task"); + CapitalistAddTask.TryAdd(target.PlayerId, 0); + CapitalistAddTask[target.PlayerId]++; + CapitalistAssignTask.TryAdd(target.PlayerId, 0); + CapitalistAssignTask[target.PlayerId]++; + Logger.Info($"{killer.GetRealName()} added a task for: {target.GetRealName()}", "Capitalist Add Task"); }); } public static bool AddTaskForPlayer(PlayerControl player) { - if (CapitalismAddTask.TryGetValue(player.PlayerId, out int amount)) + if (CapitalistAddTask.TryGetValue(player.PlayerId, out int amount)) { TaskState taskState = player.GetTaskState(); taskState.AllTasksCount += amount; - CapitalismAddTask.Remove(player.PlayerId); + CapitalistAddTask.Remove(player.PlayerId); taskState.CompletedTasksCount++; player.RpcResetTasks(false); player.SyncSettings(); diff --git a/Roles/Impostor/Gangster.cs b/Roles/Impostor/Gangster.cs index 930637398..4e83373d2 100644 --- a/Roles/Impostor/Gangster.cs +++ b/Roles/Impostor/Gangster.cs @@ -125,7 +125,7 @@ public class Gangster : RoleBase (pc.Is(CustomRoles.Marshall) && !MarshallCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.Investigator) && !InvestigatorCanBeMadmate.GetBool()) || (pc.Is(CustomRoles.President) && !PresidentCanBeMadmate.GetBool()) || - pc.Is(CustomRoles.NiceSwapper) || + pc.Is(CustomRoles.Swapper) || pc.Is(CustomRoles.Speedrunner) || pc.Is(CustomRoles.Snitch) || pc.Is(CustomRoles.LazyGuy) || diff --git a/Roles/Neutral/Executioner.cs b/Roles/Neutral/Executioner.cs index 014f351e8..51a1daacc 100644 --- a/Roles/Neutral/Executioner.cs +++ b/Roles/Neutral/Executioner.cs @@ -68,8 +68,8 @@ public class Executioner : RoleBase { List targetList = []; targetList.AddRange(from target in Main.AllPlayerControls where playerId != target.PlayerId where CanTargetImpostor.GetBool() || !target.Is(CustomRoleTypes.Impostor) where CanTargetNeutralKiller.GetBool() || !target.IsNeutralKiller() where CanTargetNeutralBenign.GetBool() || !target.IsNeutralBenign() where CanTargetNeutralEvil.GetBool() || (!target.IsNeutralEvil() && !target.IsNeutralPariah()) where CanTargetCoven.GetBool() || !target.Is(CustomRoleTypes.Coven) where target.GetCustomRole() is not (CustomRoles.GM or CustomRoles.SuperStar) where Main.LoversPlayers.TrueForAll(x => x.PlayerId != playerId) select target); - targetList.AddRange(Main.AllPlayerControls.Where(x => x.IsCrewmate() && x.GetCustomRole() is not (CustomRoles.NiceSwapper or CustomRoles.Mayor or CustomRoles.NiceGuesser or CustomRoles.Dictator))); - targetList.RemoveAll(x => x.GetCustomRole() is CustomRoles.NiceSwapper or CustomRoles.Mayor or CustomRoles.NiceGuesser or CustomRoles.Dictator or CustomRoles.Executioner or CustomRoles.Terrorist or CustomRoles.GM); + targetList.AddRange(Main.AllPlayerControls.Where(x => x.IsCrewmate() && x.GetCustomRole() is not (CustomRoles.Swapper or CustomRoles.Mayor or CustomRoles.NiceGuesser or CustomRoles.Dictator))); + targetList.RemoveAll(x => x.GetCustomRole() is CustomRoles.Swapper or CustomRoles.Mayor or CustomRoles.NiceGuesser or CustomRoles.Dictator or CustomRoles.Executioner or CustomRoles.Terrorist or CustomRoles.GM); if (!CanTargetNeutralBenign.GetBool() && !CanTargetNeutralEvil.GetBool() && !CanTargetNeutralKiller.GetBool()) targetList.RemoveAll(x => x.GetCustomRole().IsNeutral() || x.Is(CustomRoles.Bloodlust)); if (targetList.Count == 0)