From 741da0192ce42d893f47c2c56092e2c8e0e21530 Mon Sep 17 00:00:00 2001 From: Gurge44 Date: Mon, 27 May 2024 19:55:18 +0200 Subject: [PATCH] Still not done with Toilet Master --- CTA/CustomTeamAssigner/CustomRoles.cs | 1 + Modules/CustomNetObject.cs | 7 +- Modules/Utils.cs | 2 + Patches/PlayerControlPatch.cs | 3 + Roles/Crewmate/ToiletMaster.cs | 106 ++++++++++++++++++++++---- 5 files changed, 100 insertions(+), 19 deletions(-) diff --git a/CTA/CustomTeamAssigner/CustomRoles.cs b/CTA/CustomTeamAssigner/CustomRoles.cs index af718a709..6bae7887d 100644 --- a/CTA/CustomTeamAssigner/CustomRoles.cs +++ b/CTA/CustomTeamAssigner/CustomRoles.cs @@ -204,6 +204,7 @@ public enum CustomRoles Tether, TimeManager, TimeMaster, + ToiletMaster, Tornado, Tracker, Transmitter, diff --git a/Modules/CustomNetObject.cs b/Modules/CustomNetObject.cs index 2c4aae278..dd52b7648 100644 --- a/Modules/CustomNetObject.cs +++ b/Modules/CustomNetObject.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using EHR.Roles.Crewmate; -using HarmonyLib; using Hazel; using InnerNet; using UnityEngine; @@ -34,7 +33,7 @@ namespace EHR public void Despawn() { PC.Despawn(); - AllObjects.Remove(Id); + _ = new LateTask(() => AllObjects.Remove(Id), 0.001f, log: false); } protected void Hide(PlayerControl player) @@ -284,10 +283,10 @@ namespace EHR internal sealed class Toilet : CustomNetObject { - internal Toilet(Vector2 position, IEnumerable visibleList) + internal Toilet(Vector2 position, ParallelQuery hideList) { CreateNetObject("INCOMPLETE", position); - Main.AllAlivePlayerControls.ExceptBy(visibleList, x => x.PlayerId).Do(Hide); + hideList.Do(Hide); } } } \ No newline at end of file diff --git a/Modules/Utils.cs b/Modules/Utils.cs index 82ca8174b..e82b4c497 100644 --- a/Modules/Utils.cs +++ b/Modules/Utils.cs @@ -9,6 +9,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using AmongUs.Data; using AmongUs.GameOptions; +using EHR.Crewmate; using EHR.Modules; using EHR.Neutral; using EHR.Patches; @@ -2388,6 +2389,7 @@ public static class Utils CustomRoles.Sentinel => Sentinel.PatrolCooldown.GetInt(), CustomRoles.Druid => Druid.VentCooldown.GetInt(), CustomRoles.Sentry => Roles.Impostor.Sentry.ShowInfoCooldown.GetInt(), + CustomRoles.ToiletMaster => ToiletMaster.AbilityCooldown.GetInt(), CustomRoles.Sniper => Options.DefaultShapeshiftCooldown.GetInt(), CustomRoles.Assassin => Assassin.AssassinateCooldownOpt.GetInt(), CustomRoles.Undertaker => Undertaker.UndertakerAssassinateCooldown.GetInt(), diff --git a/Patches/PlayerControlPatch.cs b/Patches/PlayerControlPatch.cs index 4b068320e..e110e2449 100644 --- a/Patches/PlayerControlPatch.cs +++ b/Patches/PlayerControlPatch.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using AmongUs.GameOptions; +using EHR.Crewmate; using EHR.Modules; using EHR.Neutral; using EHR.Patches; @@ -223,6 +224,8 @@ class CheckMurderPatch return false; } + if (ToiletMaster.OnAnyoneCheckMurderStart(killer, target)) return false; + Simon.RemoveTarget(killer, Simon.Instruction.Kill); if (Mastermind.ManipulatedPlayers.ContainsKey(killer.PlayerId)) diff --git a/Roles/Crewmate/ToiletMaster.cs b/Roles/Crewmate/ToiletMaster.cs index 8e285240e..0fa012ae7 100644 --- a/Roles/Crewmate/ToiletMaster.cs +++ b/Roles/Crewmate/ToiletMaster.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using AmongUs.GameOptions; using UnityEngine; using static EHR.Options; @@ -10,27 +11,30 @@ namespace EHR.Crewmate { public static bool On; - private static OptionItem AbilityCooldown; + public static OptionItem AbilityCooldown; private static OptionItem AbilityUses; private static OptionItem ToiletDuration; private static OptionItem ToiletVisibility; private static OptionItem ToiletUseRadius; - private static OptionItem PoopDuration; + private static OptionItem ToiletUseTime; private static OptionItem BrownPoopSpeedBoost; private static OptionItem GreenPoopRadius; private static OptionItem RedPoopRadius; private static OptionItem RedPoopRoleBlockDuration; - private static OptionItem RedPoopFreezeDuration; private static OptionItem PurplePoopNotifyOnKillAttempt; public static OptionItem AbilityUseGainWithEachTaskCompleted; public static OptionItem AbilityChargesWhenFinishedTasks; - private static Dictionary PoopDurationSettings = []; + private static readonly Dictionary PoopDurationSettings = []; + private Dictionary ActivePoops = []; - Dictionary PlayersUsingToilet = []; + private Dictionary PlayersUsingToilet = []; private Dictionary Toilets = []; + static ToiletVisibilityOptions ToiletVisible => (ToiletVisibilityOptions)ToiletVisibility.GetValue(); public override bool IsEnable => On; + private static ParallelQuery EmptyParallelQuery => Enumerable.Empty().AsParallel(); + public static void SetupCustomOption() { int id = 644700; @@ -49,7 +53,7 @@ namespace EHR.Crewmate ToiletUseRadius = FloatOptionItem.Create(++id, "TM.ToiletUseRadius", new(0f, 5f, 0.25f), 1f, tab) .SetParent(CustomRoleSpawnChances[CustomRoles.ToiletMaster]) .SetValueFormat(OptionFormat.Multiplier); - PoopDuration = IntegerOptionItem.Create(++id, "TM.PoopDuration", new(0, 60, 1), 10, tab) + ToiletUseTime = IntegerOptionItem.Create(++id, "TM.ToiletUseTime", new(0, 60, 1), 5, tab) .SetParent(CustomRoleSpawnChances[CustomRoles.ToiletMaster]) .SetValueFormat(OptionFormat.Seconds); BrownPoopSpeedBoost = FloatOptionItem.Create(++id, "TM.BrownPoopSpeedBoost", new(0f, 3f, 0.05f), 0.5f, tab) @@ -64,9 +68,6 @@ namespace EHR.Crewmate RedPoopRoleBlockDuration = IntegerOptionItem.Create(++id, "TM.RedPoopRoleBlockDuration", new(0, 60, 1), 10, tab) .SetParent(CustomRoleSpawnChances[CustomRoles.ToiletMaster]) .SetValueFormat(OptionFormat.Seconds); - RedPoopFreezeDuration = IntegerOptionItem.Create(++id, "TM.RedPoopFreezeDuration", new(0, 60, 1), 10, tab) - .SetParent(CustomRoleSpawnChances[CustomRoles.ToiletMaster]) - .SetValueFormat(OptionFormat.Seconds); PurplePoopNotifyOnKillAttempt = BooleanOptionItem.Create(++id, "TM.PurplePoopNotifyOnKillAttempt", false, tab) .SetParent(CustomRoleSpawnChances[CustomRoles.ToiletMaster]); AbilityUseGainWithEachTaskCompleted = FloatOptionItem.Create(++id, "AbilityUseGainWithEachTaskCompleted", new(0f, 5f, 0.05f), 0.6f, tab) @@ -81,37 +82,74 @@ namespace EHR.Crewmate }); } - public override void Add(byte playerId) + public override void Init() { - On = true; + On = false; Toilets = []; ActivePoops = []; PlayersUsingToilet = []; } - public override void Init() + public override void Add(byte playerId) { - On = false; + On = true; + playerId.SetAbilityUseLimit(AbilityUses.GetFloat()); } public override void OnPet(PlayerControl pc) { var pos = pc.Pos(); - Toilets[pos] = (new(pos, [pc.PlayerId]), 0); + ParallelQuery hideList = ToiletVisible switch + { + ToiletVisibilityOptions.Instant => EmptyParallelQuery, + _ => Main.AllPlayerControls.Remove(pc) + }; + Toilets[pos] = (new(pos, hideList), 0); + + if (ToiletVisible == ToiletVisibilityOptions.Delayed) + _ = new LateTask(() => Toilets[pos] = (new(pos, EmptyParallelQuery), Toilets[pos].Uses), 5f, log: false); } public override void OnGlobalFixedUpdate(PlayerControl pc, bool lowLoad) { if (lowLoad || !pc.IsAlive() || !GameStates.IsInTask) return; + if (ActivePoops.TryGetValue(pc.PlayerId, out var activePoop) && activePoop.TimeStamp + PoopDurationSettings[activePoop.Poop].GetInt() <= Utils.TimeStamp) + { + ActivePoops.Remove(pc.PlayerId); + switch (activePoop.Poop) + { + case Poop.Brown: + Main.AllPlayerSpeed[pc.PlayerId] -= BrownPoopSpeedBoost.GetFloat(); + break; + case Poop.Red: + var defaultSpeed = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod); + ((List)activePoop.Data).Do(x => + { + Main.AllPlayerSpeed[x.PlayerId] = defaultSpeed; + x.MarkDirtySettings(); + }); + break; + } + } + try { var pos = pc.Pos(); var toilet = Toilets.First(x => Vector2.Distance(x.Key, pos) <= ToiletUseRadius.GetFloat()).Value; - if (toilet.Uses >= AbilityUses.GetInt() || PlayersUsingToilet.ContainsKey(pc.PlayerId)) return; + + if (toilet.Uses >= AbilityUses.GetInt()) return; + if (!PlayersUsingToilet.TryGetValue(pc.PlayerId, out var ts)) + { + PlayersUsingToilet[pc.PlayerId] = Utils.TimeStamp; + return; + } + + if (ts + ToiletUseTime.GetInt() > Utils.TimeStamp) return; toilet.Uses++; var poop = Enum.GetValues().RandomElement(); + if (poop != Poop.Green) pc.Notify(Utils.ColorString(GetPoopColor(poop), Translator.GetString($"TM.{poop}PoopNotify"))); switch (poop) { case Poop.Brown: @@ -132,10 +170,15 @@ namespace EHR.Crewmate { x.BlockRole(duration); Main.AllPlayerSpeed[x.PlayerId] = Main.MinSpeed; + x.MarkDirtySettings(); affectedPlayers.Add(x); }); ActivePoops[pc.PlayerId] = (poop, Utils.TimeStamp, affectedPlayers); break; + case Poop.Blue: + case Poop.Purple: + ActivePoops[pc.PlayerId] = (poop, Utils.TimeStamp, null); + break; } Logger.Info($"{pc.GetNameWithRole()} used a toilet => {poop} poop", "ToiletMaster"); @@ -146,6 +189,39 @@ namespace EHR.Crewmate } } + public override void AfterMeetingTasks() + { + if (ToiletVisible == ToiletVisibilityOptions.AfterMeeting) + Toilets.Values.Do(x => x.NetObject = new(Toilets.GetKeyByValue((x.NetObject, x.Uses)), EmptyParallelQuery)); + } + + static Color GetPoopColor(Poop poop) + { + return poop switch + { + Poop.Brown => Palette.Brown, + Poop.Green => Color.green, + Poop.Red => Color.red, + Poop.Purple => Palette.Purple, + Poop.Blue => Color.blue, + _ => Color.white + }; + } + + public static bool OnAnyoneCheckMurderStart(PlayerControl killer, PlayerControl target) + { + foreach (var state in Main.PlayerStates.Values) + { + if (state.Role is ToiletMaster tm && tm.ActivePoops.TryGetValue(killer.PlayerId, out var poop) && poop.Poop == Poop.Blue) + { + killer.RpcCheckAndMurder(target); + return true; + } + } + + return false; + } + enum ToiletVisibilityOptions { Instant,