Converting FixedUpdate to Coroutines (50%)

This commit is contained in:
Gurge44 committed 2026-02-08 14:08:07 +01:00
1 parent cf4c29bb00
commit 4122a5e202
12 files changed
+212 -369

No files matched your search

+1 -3
View File
@@ -982,9 +982,7 @@ internal static class CustomRolesHelper
CustomRoles.CTFPlayer or
CustomRoles.Challenger or
CustomRoles.BedWarsPlayer or
CustomRoles.Weatherman or
CustomRoles.Altruist or
CustomRoles.Duellist;
CustomRoles.Weatherman;
}
public static bool IsTaskBasedCrewmate(this CustomRoles role)
+1 -2
View File
@@ -62,8 +62,7 @@ public sealed class CountdownTimer : IDisposable
}
}
public bool IsRunning => _stopwatch.IsRunning;
public bool IsCompleted => _completed;
public Stopwatch Stopwatch => _stopwatch;
public void Start()
{
+1 -8
View File
@@ -126,7 +126,6 @@ public enum CustomRPC
Guess,
MeetingKill,
NemesisRevenge,
SetSwooperTimer,
SetBanditStealLimit,
SetBkTimer,
SyncFollowerTargetAndTimes,
@@ -136,6 +135,7 @@ public enum CustomRPC
SetCurrentRevealTarget,
RpcPassBomb,
SyncPostman,
SyncChangeling,
SetDoomsayerProgress = 209,
/*
@@ -148,7 +148,6 @@ public enum CustomRPC
*/
SetTrackerTarget = 215,
SyncChangeling,
SyncTiger,
SyncSentry,
SyncBargainer,
@@ -1113,12 +1112,6 @@ internal static class RPCHandlerPatch
Nemesis.ReceiveRPC(reader, __instance);
break;
}
case CustomRPC.SetSwooperTimer:
{
byte id = reader.ReadByte();
(Main.PlayerStates[id].Role as Swooper)?.ReceiveRPC(reader);
break;
}
case CustomRPC.SetBkTimer:
{
Wildling.ReceiveRPC(reader);
+1 -1
View File
@@ -924,7 +924,7 @@ internal static class StartGameHostPatch
}
}
if (!overrideLovers && CustomRoles.Lovers.IsEnable() && (CustomRoles.Hater.IsEnable() ? -1 : IRandom.Instance.Next(1, 100)) <= Lovers.LoverSpawnChances.GetInt()) AssignLoversRolesFromList();
if (!overrideLovers && CustomRoles.Lovers.IsEnable() && (RoleResult.ContainsValue(CustomRoles.Hater) ? -1 : IRandom.Instance.Next(1, 100)) <= Lovers.LoverSpawnChances.GetInt()) AssignLoversRolesFromList();
// Add-on assignment
var aapc = Main.EnumerateAlivePlayerControls().Shuffle();
+12 -32
View File
@@ -76,42 +76,22 @@ public class Duellist : RoleBase
duellist.RPCPlayCustomSound("Teleport");
target.RPCPlayCustomSound("Teleport");
Main.Instance.StartCoroutine(Coroutine());
System.Collections.IEnumerator Coroutine()
{
while (GameStates.IsInTask && duellist.IsAlive() && target.IsAlive()) yield return null;
if (!GameStates.IsInTask) yield break;
DuelPair.Remove(duellist.PlayerId);
if (duellist.IsAlive()) duellist.TPToRandomVent();
if (target.IsAlive()) target.TPToRandomVent();
}
}
else
duellist.Notify(GetString("TargetCannotBeTeleported"));
return false;
}
public override void OnFixedUpdate(PlayerControl pc)
{
if (DuelPair.Count == 0) return;
if (pc.IsAlive() && Count++ < 40) return;
Count = 0;
foreach (KeyValuePair<byte, byte> pair in DuelPair)
{
PlayerControl duellist = GetPlayerById(pair.Key);
PlayerControl target = GetPlayerById(pair.Value);
bool DAlive = duellist.IsAlive();
bool TAlive = target.IsAlive();
switch (DAlive)
{
case false when !TAlive:
DuelPair.Remove(pair.Key);
break;
case true when !TAlive:
DuelPair.Remove(pair.Key);
LateTask.New(() => duellist.TPToRandomVent(), 0.5f, log: false);
break;
case false:
DuelPair.Remove(pair.Key);
LateTask.New(() => target.TPToRandomVent(), 0.5f, log: false);
break;
}
}
}
}
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using EHR.Modules;
using EHR.Modules.Extensions;
using static EHR.Options;
using static EHR.Translator;
using static EHR.Utils;
@@ -12,8 +13,8 @@ public class Mastermind : RoleBase
private static List<byte> PlayerIdList = [];
public static Dictionary<byte, long> ManipulatedPlayers = [];
public static Dictionary<byte, long> ManipulateDelays = [];
public static Dictionary<byte, CountdownTimer> ManipulatedPlayers = [];
public static Dictionary<byte, CountdownTimer> ManipulateDelays = [];
private static Dictionary<byte, float> TempKCDs = [];
private static OptionItem KillCooldown;
@@ -71,91 +72,74 @@ public class Mastermind : RoleBase
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
if (!IsEnable) return false;
if (killer == null) return false;
if (target == null) return false;
if (Thanos.IsImmune(target)) return false;
return killer.CheckDoubleTrigger(target, () =>
{
killer.RPCPlayCustomSound("Line");
killer.SetKillCooldown(ManipulateCD);
ManipulateDelays.TryAdd(target.PlayerId, TimeStamp);
byte targetId = target.PlayerId;
ManipulateDelays.TryAdd(targetId, new CountdownTimer(Delay.GetInt(), () =>
{
ManipulateDelays.Remove(targetId);
if (target == null || !target.IsAlive()) return;
ManipulatedPlayers.TryAdd(targetId, new CountdownTimer(TimeLimit.GetInt(), () =>
{
ManipulatedPlayers.Remove(targetId);
if (target == null || !target.IsAlive())
{
TempKCDs.Remove(targetId);
return;
}
if (!TempKCDs.Remove(targetId)) target.RpcChangeRoleBasis(target.GetCustomRole());
LateTask.New(() => target.Suicide(realKiller: killer), 0.2f);
RPC.PlaySoundRPC(MastermindId, Sounds.KillSound);
if (target.AmOwner)
Achievements.Type.OutOfTime.Complete();
}, onTick: () =>
{
if (target == null || !target.IsAlive() || !ManipulatedPlayers.TryGetValue(targetId, out var timer))
{
ManipulatedPlayers.Remove(targetId);
TempKCDs.Remove(targetId);
return;
}
target.Notify(string.Format(GetString("ManipulateNotify"), (int)timer.Remaining.TotalSeconds), 3f, true);
}, onCanceled: () =>
{
ManipulatedPlayers.Remove(targetId);
TempKCDs.Remove(targetId);
}));
if (target.HasKillButton()) TempKCDs.TryAdd(targetId, Main.KillTimers[targetId]);
else target.RpcChangeRoleBasis(CustomRoles.SerialKiller);
target.SetKillCooldown(1f);
NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
}, onCanceled: () => ManipulateDelays.Remove(targetId)));
NotifyRoles(SpecifySeer: killer, SpecifyTarget: target);
});
}
private long LastUpdate;
public override void OnFixedUpdate(PlayerControl _)
{
if (!IsEnable || GameStates.IsMeeting || (ManipulatedPlayers.Count == 0 && ManipulateDelays.Count == 0)) return;
long now = TimeStamp;
if (now == LastUpdate) return;
LastUpdate = now;
foreach (KeyValuePair<byte, long> x in ManipulateDelays)
{
PlayerControl pc = GetPlayerById(x.Key);
if (!pc.IsAlive())
{
ManipulateDelays.Remove(x.Key);
continue;
}
if (x.Value + Delay.GetInt() < now)
{
ManipulateDelays.Remove(x.Key);
ManipulatedPlayers.TryAdd(x.Key, now);
if (pc.HasKillButton()) TempKCDs.TryAdd(pc.PlayerId, Main.KillTimers[pc.PlayerId]);
else pc.RpcChangeRoleBasis(CustomRoles.SerialKiller);
pc.SetKillCooldown(1f);
NotifyRoles(SpecifySeer: MastermindPC, SpecifyTarget: pc);
}
}
foreach (KeyValuePair<byte, long> x in ManipulatedPlayers)
{
PlayerControl player = GetPlayerById(x.Key);
if (!player.IsAlive())
{
ManipulatedPlayers.Remove(x.Key);
TempKCDs.Remove(x.Key);
continue;
}
if (x.Value + TimeLimit.GetInt() < now)
{
ManipulatedPlayers.Remove(x.Key);
if (!TempKCDs.Remove(x.Key)) player.RpcChangeRoleBasis(player.GetCustomRole());
player.Suicide(realKiller: MastermindPC);
RPC.PlaySoundRPC(MastermindId, Sounds.KillSound);
if (player.AmOwner)
Achievements.Type.OutOfTime.Complete();
}
long time = TimeLimit.GetInt() - (now - x.Value);
player.Notify(string.Format(GetString("ManipulateNotify"), time), 3f, true);
}
}
public override void OnReportDeadBody()
{
if (!IsEnable) return;
foreach (KeyValuePair<byte, long> x in ManipulatedPlayers)
foreach (KeyValuePair<byte, CountdownTimer> x in ManipulatedPlayers)
{
x.Value.Dispose();
PlayerControl pc = GetPlayerById(x.Key);
if (pc.IsAlive()) pc.Suicide(realKiller: MastermindPC);
if (pc != null && pc.IsAlive()) pc.Suicide(realKiller: MastermindPC);
}
ManipulateDelays.Values.Do(x => x.Dispose());
ManipulateDelays.Clear();
ManipulatedPlayers.Clear();
TempKCDs.Clear();
@@ -166,6 +150,7 @@ public class Mastermind : RoleBase
if (killer == null) return false;
if (target == null) return false;
ManipulatedPlayers[killer.PlayerId].Dispose();
ManipulatedPlayers.Remove(killer.PlayerId);
foreach (byte id in PlayerIdList) (Main.PlayerStates[id].Role as Mastermind)?.NotifyMastermindTargetSurvived();
@@ -84,7 +84,6 @@ public class RiftMaker : RoleBase
{
if (!GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks) return;
if (Pelican.IsEaten(player.PlayerId) || !player.IsAlive()) return;
if (!player.Is(CustomRoles.RiftMaker)) return;
if (Marks.Count != 2) return;
if (Vector2.Distance(Marks[0], Marks[1]) <= 4f)
@@ -95,33 +94,16 @@ public class RiftMaker : RoleBase
return;
}
if (LastTP + 5 > TimeStamp) return;
long now = TimeStamp;
if (LastTP + 5 > now) return;
Vector2 position = player.Pos();
Vector2 pos = player.Pos();
if (!Marks.FindFirst(x => Vector2.Distance(x, pos) <= 1f, out Vector2 nearMark)) return;
var tp = false;
Vector2 from = Marks[0];
foreach (Vector2 mark in Marks)
{
float dis = Vector2.Distance(mark, position);
if (dis > 2f) continue;
tp = true;
from = mark;
}
if (tp)
{
LastTP = TimeStamp;
if (from == Marks[0])
player.TP(Marks[1]);
else if (from == Marks[1])
player.TP(Marks[0]);
else
Logger.Error($"Teleport failed - from: {from}", "RiftMakerTP");
}
int index = Marks.IndexOf(nearMark);
Vector2 target = Marks[1 - index];
player.TP(target);
LastTP = now;
}
public override void OnReportDeadBody()
+16 -21
View File
@@ -20,7 +20,6 @@ public sealed class Stealth : RoleBase
public static bool On;
public PlayerControl[] darkenedPlayers;
private SystemTypes? darkenedRoom;
private float darkenTimer;
private float darkenDuration;
private bool excludeImpostors;
@@ -88,6 +87,12 @@ public sealed class Stealth : RoleBase
Main.PlayerStates[player.PlayerId].IsBlackOut = true;
player.MarkDirtySettings();
}
LateTask.New(() =>
{
if (ReportDeadBodyPatch.MeetingStarted || !GameStates.IsInTask || darkenedPlayers == null) return;
ResetDarkenState(false);
}, darkenDuration);
if (!useLegacyVersion && Utils.DoRPC)
{
@@ -121,7 +126,6 @@ public sealed class Stealth : RoleBase
useLegacyVersion = UseLegacyVersion.GetBool();
blindingRadius = OptionBlindingRadius.GetFloat();
abilityCooldown = AbilityCooldown.GetInt();
darkenTimer = darkenDuration;
}
public override void Add(byte playerId)
@@ -130,20 +134,9 @@ public sealed class Stealth : RoleBase
StealthPC = playerId.GetPlayer();
}
public override void OnFixedUpdate(PlayerControl player)
{
if (!AmongUsClient.Instance.AmHost) return;
if (darkenedPlayers != null)
{
darkenTimer -= Time.fixedDeltaTime;
if (darkenTimer <= 0) ResetDarkenState();
}
}
public override void OnReportDeadBody()
{
if (AmongUsClient.Instance.AmHost) ResetDarkenState();
if (AmongUsClient.Instance.AmHost) ResetDarkenState(true);
}
private void RpcDarken(SystemTypes? roomType)
@@ -174,31 +167,33 @@ public sealed class Stealth : RoleBase
darkenedRoom = roomId == byte.MaxValue ? null : (SystemTypes)roomId;
}
private void ResetDarkenState()
private void ResetDarkenState(bool meeting)
{
if (darkenedPlayers != null)
{
foreach (PlayerControl player in darkenedPlayers)
if (!meeting)
{
Main.PlayerStates[player.PlayerId].IsBlackOut = false;
player.MarkDirtySettings();
foreach (PlayerControl player in darkenedPlayers)
{
Main.PlayerStates[player.PlayerId].IsBlackOut = false;
player.MarkDirtySettings();
}
}
darkenedPlayers = null;
}
darkenTimer = darkenDuration;
if (!useLegacyVersion)
{
Utils.SendRPC(CustomRPC.SyncRoleData, StealthPC.PlayerId, 0);
if (!Options.UsePets.GetBool() || Options.UsePhantomBasis.GetBool())
if (!meeting && (!Options.UsePets.GetBool() || Options.UsePhantomBasis.GetBool()))
StealthPC.RpcResetAbilityCooldown();
}
else
RpcDarken(null);
if (meeting) return;
Utils.NotifyRoles(SpecifySeer: StealthPC);
}
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using AmongUs.GameOptions;
using AmongUs.GameOptions;
namespace EHR.Roles;
@@ -8,7 +7,6 @@ internal class Swiftclaw : RoleBase
public static OptionItem DashCD;
public static OptionItem DashDuration;
public static OptionItem DashSpeed;
private static readonly Dictionary<byte, (long StartTimeStamp, float NormalSpeed)> DashStart = [];
public static bool On;
private static int Id => 643340;
@@ -33,7 +31,6 @@ internal class Swiftclaw : RoleBase
public override void Init()
{
DashStart.Clear();
On = false;
}
@@ -68,28 +65,16 @@ internal class Swiftclaw : RoleBase
private static void Dash(PlayerControl pc)
{
if (pc == null || DashStart.ContainsKey(pc.PlayerId)) return;
DashStart[pc.PlayerId] = (Utils.TimeStamp, Main.AllPlayerSpeed[pc.PlayerId]);
Main.AllPlayerSpeed[pc.PlayerId] = DashSpeed.GetFloat();
pc.MarkDirtySettings();
}
public override void OnFixedUpdate(PlayerControl pc)
{
if (!GameStates.IsInTask || pc == null || !DashStart.TryGetValue(pc.PlayerId, out (long StartTimeStamp, float NormalSpeed) dashInfo) || dashInfo.StartTimeStamp + DashDuration.GetInt() > Utils.TimeStamp) return;
Main.AllPlayerSpeed[pc.PlayerId] = dashInfo.NormalSpeed;
pc.MarkDirtySettings();
DashStart.Remove(pc.PlayerId);
}
public override void OnReportDeadBody()
{
foreach (KeyValuePair<byte, (long StartTimeStamp, float NormalSpeed)> item in DashStart)
Main.AllPlayerSpeed[item.Key] = item.Value.NormalSpeed;
DashStart.Clear();
LateTask.New(() =>
{
if (Main.RealOptionsData == null) return;
Main.AllPlayerSpeed[pc.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
if (!GameStates.IsInTask || ExileController.Instance || AntiBlackout.SkipTasks) return;
pc.MarkDirtySettings();
}, DashDuration.GetInt(), "Swiftclaw Dash End");
}
public override void SetButtonTexts(HudManager hud, byte id)
+70 -109
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Modules.Extensions;
using Hazel;
using static EHR.Options;
using static EHR.Translator;
@@ -20,26 +21,21 @@ public class Swooper : RoleBase
private static OptionItem SwooperLimitOpt;
public static OptionItem SwooperAbilityUseGainWithEachKill;
private int CD;
private CountdownTimer CooldownTimer;
private CountdownTimer InvisTimer;
private CustomRoles UsedRole;
private float Cooldown;
private int Count;
private float Duration;
private long InvisTime;
private bool CanVent;
private long lastFixedTime;
private long lastTime;
private bool VentNormallyOnCooldown;
private byte SwooperId;
private CustomRoles UsedRole;
private int ventedId;
private bool VentNormallyOnCooldown;
public override bool IsEnable => PlayerIdList.Count > 0;
private bool CanGoInvis => GameStates.IsInTask && InvisTime == -10 && lastTime == -10;
private bool IsInvis => InvisTime != -10;
private bool CanGoInvis => GameStates.IsInTask && !ExileController.Instance && !AntiBlackout.SkipTasks && InvisTimer == null && CooldownTimer == null;
private bool IsInvis => InvisTimer != null;
public override void SetupCustomOption()
{
@@ -78,11 +74,6 @@ public class Swooper : RoleBase
PlayerIdList.Add(playerId);
SwooperId = playerId;
InvisTime = -10;
lastTime = -10;
ventedId = -10;
CD = 0;
UsedRole = Main.PlayerStates[playerId].MainRole;
switch (UsedRole)
@@ -108,6 +99,9 @@ public class Swooper : RoleBase
CanVent = Wraith.WraithCanVent.GetBool();
break;
}
InvisTimer = null;
StartCooldownTimer();
}
public override void Remove(byte playerId)
@@ -144,92 +138,60 @@ public class Swooper : RoleBase
return UsedRole != CustomRoles.Chameleon && CanVent;
}
private void SendRPC()
public override void AfterMeetingTasks()
{
if (!IsEnable || !Utils.DoRPC) return;
InvisTimer = null;
StartCooldownTimer();
}
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetSwooperTimer, SendOption.Reliable);
writer.Write(SwooperId);
writer.Write(InvisTime.ToString());
writer.Write(lastTime.ToString());
AmongUsClient.Instance.FinishRpcImmediately(writer);
private void StartCooldownTimer()
{
CooldownTimer = new CountdownTimer(Cooldown, () =>
{
CooldownTimer = null;
if (!AmongUsClient.Instance.AmHost) return;
var player = SwooperId.GetPlayer();
if (player == null || !player.IsAlive()) return;
if (!player.IsModdedClient() && !(UsedRole != CustomRoles.Chameleon && UsePhantomBasis.GetBool() && (UsedRole != CustomRoles.Wraith || UsePhantomBasisForNKs.GetBool())))
player.Notify(GetString("SwooperCanVent"), 10f);
}, onTick: () =>
{
if (!AmongUsClient.Instance.AmHost) return;
var player = SwooperId.GetPlayer();
if (player == null || !player.IsAlive()) return;
if (!(UsePhantomBasis.GetBool() && (UsedRole != CustomRoles.Wraith || UsePhantomBasisForNKs.GetBool())))
player.Notify(string.Format(GetString("CDPT"), (int)Math.Ceiling(CooldownTimer.Remaining.TotalSeconds)), 3f, true);
}, onCanceled: () => CooldownTimer = null);
Utils.SendRPC(CustomRPC.SyncRoleData, SwooperId, true);
}
private void StartInvisTimer(PlayerControl player, int ventId = 0)
{
InvisTimer = new CountdownTimer(Duration, () =>
{
InvisTimer = null;
if (UsedRole == CustomRoles.Chameleon && !UsePets.GetBool())
Main.EnumeratePlayerControls().Without(player).Do(x => player.MyPhysics.RpcExitVentDesync(ventId, x));
else
player.RpcMakeVisible(phantom: UsedRole == CustomRoles.Swooper);
player.Notify(GetString("SwooperInvisStateOut"));
player.RpcResetAbilityCooldown();
}, onTick: player.IsModdedClient() ? null : () => player.Notify(string.Format(GetString("SwooperInvisStateCountdown"), (int)InvisTimer.Remaining.TotalSeconds), overrideAll: true), onCanceled: () => InvisTimer = null);
Utils.SendRPC(CustomRPC.SyncRoleData, SwooperId, false);
}
public void ReceiveRPC(MessageReader reader)
{
InvisTime = long.Parse(reader.ReadString());
lastTime = long.Parse(reader.ReadString());
}
public override void AfterMeetingTasks()
{
InvisTime = -10;
lastTime = Utils.TimeStamp;
SendRPC();
}
public override void OnFixedUpdate(PlayerControl player)
{
if (!GameStates.IsInTask || !IsEnable || Main.HasJustStarted || ExileController.Instance || player == null) return;
if (Count++ < 30) return;
Count = 0;
long now = Utils.TimeStamp;
if (lastTime != -10)
{
if (!player.IsModdedClient() && UsedRole != CustomRoles.Chameleon)
{
long cooldown = lastTime + (long)Cooldown - now;
if ((int)cooldown != CD && !(UsePhantomBasis.GetBool() && (UsedRole != CustomRoles.Wraith || UsePhantomBasisForNKs.GetBool())))
player.Notify(string.Format(GetString("CDPT"), cooldown + 1), 3f, true);
CD = (int)cooldown;
}
if (lastTime + (long)Cooldown < now)
{
lastTime = -10;
if (!player.IsModdedClient() && !(UsedRole != CustomRoles.Chameleon && UsePhantomBasis.GetBool() && (UsedRole != CustomRoles.Wraith || UsePhantomBasisForNKs.GetBool())))
player.Notify(GetString("SwooperCanVent"), 10f);
SendRPC();
CD = 0;
}
}
if (lastFixedTime != now && IsInvis)
{
lastFixedTime = now;
long remainTime = InvisTime + (long)Duration - now;
switch (remainTime)
{
case < 0:
lastTime = now;
if (UsedRole == CustomRoles.Chameleon && !UsePets.GetBool())
{
int ventId = ventedId == -10 ? Main.LastEnteredVent[player.PlayerId].Id : ventedId;
Main.EnumeratePlayerControls().Without(player).Do(x => player.MyPhysics.RpcExitVentDesync(ventId, x));
}
else
player.RpcMakeVisible(phantom: UsedRole == CustomRoles.Swooper);
player.Notify(GetString("SwooperInvisStateOut"));
player.RpcResetAbilityCooldown();
InvisTime = -10;
SendRPC();
break;
case <= 10 when !player.IsModdedClient():
player.Notify(string.Format(GetString("SwooperInvisStateCountdown"), remainTime + 1), overrideAll: true);
break;
}
}
if (reader.ReadBoolean()) CooldownTimer = new CountdownTimer(Cooldown, () => CooldownTimer = null, onCanceled: () => CooldownTimer = null);
else InvisTimer = new CountdownTimer(Duration, () => InvisTimer = null, onCanceled: () => InvisTimer = null);
}
bool OnCoEnterVent(PlayerPhysics __instance, int ventId)
@@ -245,11 +207,10 @@ public class Swooper : RoleBase
{
LateTask.New(() => __instance.RpcExitVentDesync(ventId, pc), 0.5f);
ventedId = ventId;
InvisTime = Utils.TimeStamp;
StartInvisTimer(pc, ventId);
if (!wraith) pc.RpcRemoveAbilityUse();
SendRPC();
pc.Notify(GetString("SwooperInvisState"), Duration);
return true;
}
@@ -268,11 +229,11 @@ public class Swooper : RoleBase
{
if (OnCoEnterVent(pc.MyPhysics, vent.Id)) return;
if (!IsInvis || InvisTime == Utils.TimeStamp) return;
if (!IsInvis || InvisTimer.Stopwatch.Elapsed.TotalSeconds < 1) return;
InvisTime = -10;
lastTime = Utils.TimeStamp;
SendRPC();
InvisTimer.Dispose();
InvisTimer = null;
StartCooldownTimer();
pc.Notify(GetString("SwooperInvisStateOut"), 10f);
pc.RpcResetAbilityCooldown();
@@ -289,10 +250,10 @@ public class Swooper : RoleBase
{
pc.RpcMakeInvisible(phantom: UsedRole == CustomRoles.Swooper);
InvisTime = Utils.TimeStamp;
StartInvisTimer(pc);
if (!wraith) pc.RpcRemoveAbilityUse();
SendRPC();
pc.Notify(GetString("SwooperInvisState"), Duration);
}
@@ -312,14 +273,14 @@ public class Swooper : RoleBase
if (IsInvis)
{
long remainTime = InvisTime + (long)Duration - Utils.TimeStamp;
int remainTime = (int)InvisTimer.Remaining.TotalSeconds;
str.Append(string.Format(GetString("SwooperInvisStateCountdown"), remainTime + 1));
}
else if (!(UsedRole != CustomRoles.Chameleon && UsePhantomBasis.GetBool() && (UsedRole != CustomRoles.Wraith || UsePhantomBasisForNKs.GetBool())))
{
if (lastTime != -10)
if (CooldownTimer != null)
{
long cooldown = lastTime + (long)Cooldown - Utils.TimeStamp;
int cooldown = (int)Math.Ceiling(CooldownTimer.Remaining.TotalSeconds);
str.Append(string.Format(GetString("SwooperInvisCooldownRemain"), cooldown + 1));
}
else
+14 -36
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Modules.Extensions;
using UnityEngine;
using static EHR.Translator;
@@ -12,7 +13,7 @@ public class Vampire : RoleBase
{
private const int Id = 4500;
private static readonly List<byte> PlayerIdList = [];
private static readonly Dictionary<byte, BittenInfo> BittenPlayers = [];
private static readonly HashSet<byte> BittenPlayers = [];
private static OptionItem Cooldown;
private static OptionItem OptionKillDelay;
@@ -24,6 +25,8 @@ public class Vampire : RoleBase
private float KillCooldown;
private float KillDelay;
private byte VampireId;
public override bool IsEnable => PlayerIdList.Count > 0;
public override void SetupCustomOption()
@@ -52,6 +55,7 @@ public class Vampire : RoleBase
{
PlayerIdList.Add(playerId);
VampireId = playerId;
IsPoisoner = Main.PlayerStates[playerId].MainRole == CustomRoles.Poisoner;
if (!IsPoisoner)
@@ -108,34 +112,15 @@ public class Vampire : RoleBase
{
killer.SetKillCooldown(KillCooldown + KillDelay);
killer.RPCPlayCustomSound("Bite");
BittenPlayers.Add(target.PlayerId);
if (!BittenPlayers.ContainsKey(target.PlayerId)) BittenPlayers.Add(target.PlayerId, new(killer.PlayerId, 0f));
}
}
public override void OnFixedUpdate(PlayerControl vampire)
{
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInTask || ExileController.Instance) return;
byte vampireID = vampire.PlayerId;
List<byte> targetList = [.. BittenPlayers.Where(b => b.Value.VampireId == vampireID).Select(b => b.Key)];
foreach (byte targetId in targetList.ToArray())
{
BittenInfo bitten = BittenPlayers[targetId];
if (bitten.KillTimer >= KillDelay)
_ = new CountdownTimer(KillDelay, () =>
{
PlayerControl target = Utils.GetPlayerById(targetId);
KillBitten(vampire, target);
BittenPlayers.Remove(targetId);
}
else
{
bitten.KillTimer += Time.fixedDeltaTime;
BittenPlayers[targetId] = bitten;
}
if (target == null || !target.IsAlive()) return;
KillBitten(killer, target);
BittenPlayers.Remove(target.PlayerId);
}, onCanceled: BittenPlayers.Clear);
}
}
@@ -160,12 +145,12 @@ public class Vampire : RoleBase
{
try
{
foreach (byte targetId in BittenPlayers.Keys)
foreach (byte targetId in BittenPlayers)
{
try
{
PlayerControl target = Utils.GetPlayerById(targetId);
PlayerControl vampire = Utils.GetPlayerById(BittenPlayers[targetId].VampireId);
PlayerControl vampire = Utils.GetPlayerById(VampireId);
KillBitten(vampire, target, meeting: true);
}
catch (Exception e) { Utils.ThrowException(e); }
@@ -180,11 +165,4 @@ public class Vampire : RoleBase
{
hud.KillButton.OverrideText(GetString(IsPoisoner ? "PoisonerKillButtonText" : "VampireBiteButtonText"));
}
private class BittenInfo(byte vampierId, float killTimer)
{
public readonly byte VampireId = vampierId;
public float KillTimer = killTimer;
}
}
+25 -38
View File
@@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Modules.Extensions;
using Hazel;
using UnityEngine;
using static EHR.Options;
@@ -24,10 +26,12 @@ internal class Warlock : RoleBase
public static Dictionary<byte, PlayerControl> CursedPlayers = [];
public static Dictionary<byte, bool> IsCurseAndKill = [];
public static bool IsCursed;
private float CurseCD;
private float KCD;
private CountdownTimer CurseCD;
private CountdownTimer KCD;
private long LastNotify;
private byte WarlockId;
public override bool IsEnable => On;
public override void SetupCustomOption()
@@ -63,10 +67,12 @@ internal class Warlock : RoleBase
public override void Add(byte playerId)
{
On = true;
WarlockId = playerId;
CursedPlayers[playerId] = null;
IsCurseAndKill[playerId] = false;
KCD = KillCooldown.GetFloat();
CurseCD = CurseCooldown.GetFloat();
PlayerControl pc = playerId.GetPlayer();
KCD = new CountdownTimer(KillCooldown.GetFloat() + 8, () => KCD = null, onTick: () => Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc, SendOption: SendOption.None), onCanceled: () => KCD = null);
CurseCD = new CountdownTimer(CurseCooldown.GetFloat() + 8, () => CurseCD = null, onTick: () => Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc, SendOption: SendOption.None), onCanceled: () => CurseCD = null);
LastNotify = 0;
}
@@ -110,13 +116,16 @@ internal class Warlock : RoleBase
if (!shapeshifting && curse) hud.AbilityButton?.OverrideText(Translator.GetString("WarlockShapeshiftButtonText"));
}
private void ResetCooldowns(bool killCooldown = false, bool curseCooldown = false, bool shapeshiftCooldown = false, PlayerControl warlock = null)
private void ResetCooldowns(bool killCooldown = false, bool curseCooldown = false, bool shapeshiftCooldown = false, PlayerControl warlockPc = null)
{
if (killCooldown) KCD = KillCooldown.GetFloat();
var warlock = warlockPc ?? WarlockId.GetPlayer();
if (warlock == null || !warlock.IsAlive()) return;
if (curseCooldown) CurseCD = CurseCooldown.GetFloat();
if (warlock == null) return;
float kcd = KillCooldown.GetFloat();
float ccd = CurseCooldown.GetFloat();
if (killCooldown) KCD = new CountdownTimer(kcd, () => KCD = null, onTick: () => Utils.NotifyRoles(SpecifySeer: warlock, SpecifyTarget: warlock, SendOption: SendOption.None), onCanceled: () => KCD = null);
if (curseCooldown) CurseCD = new CountdownTimer(ccd, () => CurseCD = null, onTick: () => Utils.NotifyRoles(SpecifySeer: warlock, SpecifyTarget: warlock, SendOption: SendOption.None), onCanceled: () => CurseCD = null);
if (shapeshiftCooldown)
{
@@ -126,7 +135,7 @@ internal class Warlock : RoleBase
warlock.AddAbilityCD();
}
if (KCD > 0f && CurseCD > 0f) LateTask.New(() => { warlock.SetKillCooldown(Math.Min(KCD, CurseCD) - 1f); }, 0.1f, log: false);
if (killCooldown && curseCooldown) warlock.SetKillCooldown(Math.Min(kcd, ccd) - 1f);
Utils.NotifyRoles(SpecifySeer: warlock, SpecifyTarget: warlock);
}
@@ -139,7 +148,7 @@ internal class Warlock : RoleBase
if (killer.CheckDoubleTrigger(target, () =>
{
if (CurseCD > 0f) return;
if (CurseCD != null) return;
IsCurseAndKill.TryAdd(killer.PlayerId, false);
@@ -155,7 +164,7 @@ internal class Warlock : RoleBase
WarlockTimer[killer.PlayerId] = 0f;
IsCurseAndKill[killer.PlayerId] = true;
ResetCooldowns(true, true, warlock: killer);
ResetCooldowns(true, true, warlockPc: killer);
return;
}
@@ -163,7 +172,7 @@ internal class Warlock : RoleBase
if (IsCurseAndKill[killer.PlayerId]) killer.RpcGuardAndKill(target);
}))
{
if (KCD > 0f) return false;
if (KCD != null) return false;
ResetCooldowns(true, true, true, killer);
@@ -287,26 +296,6 @@ internal class Warlock : RoleBase
}
}
public override void OnFixedUpdate(PlayerControl pc)
{
if (!GameStates.IsInTask || !pc.IsAlive() || pc.inVent) return;
float beforeKCD = KCD;
float beforeCCD = CurseCD;
if (KCD > 0f) KCD -= Time.fixedDeltaTime;
if (CurseCD > 0f) CurseCD -= Time.fixedDeltaTime;
long now = Utils.TimeStamp;
if ((Math.Abs(KCD - beforeKCD) > 0.01f || Math.Abs(beforeCCD - CurseCD) > 0.01f) && LastNotify != now)
{
LastNotify = now;
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
}
public override void AfterMeetingTasks()
{
ResetCooldowns(true, true);
@@ -314,13 +303,11 @@ internal class Warlock : RoleBase
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
{
if (seer.IsModdedClient() && !hud || Main.PlayerStates[seer.PlayerId].Role is not Warlock { IsEnable: true } wl || seer.PlayerId != target.PlayerId) return string.Empty;
if (seer.PlayerId != WarlockId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || meeting) return string.Empty;
var sb = new StringBuilder();
if (wl.KCD > 0f) sb.Append($"<#ffa500>{Translator.GetString("KillCooldown")}:</color> <#ffffff>{(int)Math.Round(wl.KCD)}s</color>");
if (wl.CurseCD > 0f) sb.Append($"{(sb.Length > 0 ? "\n" : string.Empty)}<#00ffa5>{Translator.GetString("CurseCooldown")}:</color> <#ffffff>{(int)Math.Round(wl.CurseCD)}s</color>");
if (KCD != null) sb.Append($"<#ffa500>{Translator.GetString("KillCooldown")}:</color> <#ffffff>{(int)Math.Ceiling(KCD.Remaining.TotalSeconds)}s</color>");
if (CurseCD != null) sb.Append($"{(sb.Length > 0 ? "\n" : string.Empty)}<#00ffa5>{Translator.GetString("CurseCooldown")}:</color> <#ffffff>{(int)Math.Ceiling(CurseCD.Remaining.TotalSeconds)}s</color>");
return hud ? sb.ToString() : $"<size=1.7>{sb}</size>";
}
}