mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
Converting FixedUpdate to Coroutines (50%)
This commit is contained in:
1 parent
cf4c29bb00
commit
4122a5e202
12 files changed
+212
-369
No files matched your search
@@ -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)
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>";
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user