Files
EndlessHostRoles/Roles/Standard/Neutral/Killing/Sprayer.cs
T
2026-05-19 12:32:31 +02:00

202 lines
6.9 KiB
C#

using System;
using System.Collections.Generic;
using AmongUs.GameOptions;
using static EHR.Options;
using static EHR.Translator;
using static EHR.Utils;
namespace EHR.Roles;
internal class Sprayer : RoleBase
{
private static byte SprayerId = byte.MaxValue;
private static OptionItem KillCooldown;
private static OptionItem HasImpostorVision;
public static OptionItem CanVent;
private static OptionItem CD;
private static OptionItem UseLimitOpt;
public static OptionItem LoweredVision;
private static OptionItem LoweredSpeed;
private static OptionItem EffectDuration;
private static OptionItem MaxTrappedTimes;
private static readonly Dictionary<Vector2, SprayedArea> Traps = [];
private static readonly Dictionary<byte, int> TrappedCount = [];
public static readonly List<byte> LowerVisionList = [];
private static readonly Dictionary<byte, long> LastUpdate = [];
private static int Id => 643240;
private static PlayerControl SprayerPC => GetPlayerById(SprayerId);
public override bool IsEnable => SprayerId != byte.MaxValue;
public override void SetupCustomOption()
{
SetupRoleOptions(Id, TabGroup.NeutralRoles, CustomRoles.Sprayer);
KillCooldown = new FloatOptionItem(Id + 2, "KillCooldown", new(0f, 180f, 0.5f), 22.5f, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer])
.SetValueFormat(OptionFormat.Seconds);
HasImpostorVision = new BooleanOptionItem(Id + 3, "ImpostorVision", true, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer]);
CanVent = new BooleanOptionItem(Id + 4, "CanVent", true, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer]);
CD = new IntegerOptionItem(Id + 5, "AbilityCooldown", new(0, 90, 1), 15, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer])
.SetValueFormat(OptionFormat.Seconds);
UseLimitOpt = new IntegerOptionItem(Id + 6, "AbilityUseLimit", new(1, 90, 1), 5, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer])
.SetValueFormat(OptionFormat.Times);
LoweredVision = new FloatOptionItem(Id + 7, "FFA_LowerVision", new(0.05f, 1.5f, 0.05f), 0.25f, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer])
.SetValueFormat(OptionFormat.Multiplier);
LoweredSpeed = new FloatOptionItem(Id + 8, "FFA_DecreasedSpeed", new(0.05f, 3f, 0.05f), 0.8f, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer])
.SetValueFormat(OptionFormat.Multiplier);
EffectDuration = new IntegerOptionItem(Id + 10, "NegativeEffectDuration", new(1, 90, 1), 10, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer])
.SetValueFormat(OptionFormat.Seconds);
MaxTrappedTimes = new IntegerOptionItem(Id + 9, "SprayerMaxTrappedTimes", new(1, 90, 1), 3, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Sprayer])
.SetValueFormat(OptionFormat.Times);
}
public override void Init()
{
SprayerId = byte.MaxValue;
Traps.Clear();
TrappedCount.Clear();
LowerVisionList.Clear();
LastUpdate.Clear();
}
public override void Add(byte playerId)
{
SprayerId = playerId;
playerId.SetAbilityUseLimit(UseLimitOpt.GetFloat());
foreach (PlayerControl pc in Main.CachedAlivePlayerControls()) TrappedCount[pc.PlayerId] = 0;
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = KillCooldown.GetFloat();
}
public override bool CanUseImpostorVentButton(PlayerControl pc)
{
return CanVent.GetBool();
}
public override bool CanUseSabotage(PlayerControl pc)
{
return base.CanUseSabotage(pc) || (pc.IsAlive() && !(UsePhantomBasis.GetBool() && UsePhantomBasisForNKs.GetBool()));
}
public override void ApplyGameOptions(IGameOptions opt, byte id)
{
opt.SetVision(HasImpostorVision.GetBool());
if (UsePhantomBasis.GetBool() && UsePhantomBasisForNKs.GetBool()) AURoleOptions.PhantomCooldown = CD.GetInt();
}
public override bool OnSabotage(PlayerControl pc)
{
PlaceTrap();
return pc.Is(CustomRoles.Mischievous);
}
public override void OnPet(PlayerControl pc)
{
PlaceTrap();
}
public override bool OnVanish(PlayerControl pc)
{
PlaceTrap();
return false;
}
public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
{
if (!shapeshifting) return true;
PlaceTrap();
return false;
}
private void PlaceTrap()
{
if (!IsEnable || SprayerId.GetAbilityUseLimit() <= 0 || SprayerPC.HasAbilityCD()) return;
Vector2 pos = SprayerPC.Pos();
Traps[pos] = new(pos, SprayerPC);
SprayerPC.RpcRemoveAbilityUse();
if (SprayerId.GetAbilityUseLimit() > 0) SprayerPC.AddAbilityCD(CD.GetInt());
SprayerPC.Notify(GetString("SprayerNotify"));
}
public override void OnCheckPlayerPosition(PlayerControl pc)
{
if (!IsEnable || !GameStates.IsInTask || Traps.Count == 0) return;
long now = TimeStamp;
if (pc.PlayerId == SprayerId) return;
LastUpdate.TryAdd(pc.PlayerId, now);
if (LastUpdate[pc.PlayerId] + 3 > now) return;
LastUpdate[pc.PlayerId] = now;
foreach (KeyValuePair<Vector2, SprayedArea> trap in Traps)
{
if (FastVector2.DistanceWithinRange(pc.Pos(), trap.Key, 2f))
{
byte playerId = pc.PlayerId;
float tempSpeed = Main.AllPlayerSpeed[playerId];
Main.AllPlayerSpeed[playerId] = LoweredSpeed.GetFloat();
LowerVisionList.Add(playerId);
TrappedCount[playerId]++;
if (TrappedCount[playerId] > MaxTrappedTimes.GetInt())
{
pc.Suicide(realKiller: SprayerPC);
TrappedCount.Remove(playerId);
}
else
{
pc.MarkDirtySettings();
LateTask.New(() =>
{
Main.AllPlayerSpeed[playerId] = tempSpeed;
LowerVisionList.Remove(playerId);
if (GameStates.IsInTask) pc.MarkDirtySettings();
}, EffectDuration.GetFloat(), "Sprayer Revert Effects");
}
}
}
}
public override void OnReportDeadBody()
{
Traps.Clear();
}
public override void AfterMeetingTasks()
{
if (Main.PlayerStates[SprayerId].IsDead) return;
if (SprayerId.GetAbilityUseLimit() > 0) SprayerPC.AddAbilityCD(Math.Max(15, CD.GetInt()));
}
}