Files
EndlessHostRoles/Roles/Standard/Neutral/Evil/Arsonist.cs
T
2026-06-18 10:42:28 +02:00

266 lines
11 KiB
C#

using System.Collections.Generic;
using System.Linq;
using AmongUs.GameOptions;
using EHR.Modules;
using UnityEngine;
using static EHR.Options;
namespace EHR.Roles;
internal class Arsonist : RoleBase
{
public static Dictionary<byte, (PlayerControl Player, float Timer)> ArsonistTimer = [];
public static Dictionary<(byte, byte), bool> IsDoused = [];
public static byte CurrentDousingTarget = byte.MaxValue;
public static OptionItem ArsonistDouseTime;
public static OptionItem ArsonistCooldown;
public static OptionItem ArsonistKeepsGameGoing;
public static OptionItem ArsonistCanIgniteAnytime;
public static OptionItem ArsonistMinPlayersToIgnite;
public static OptionItem ArsonistMaxPlayersToIgnite;
public static OptionItem ArsonistCanVent;
public static OptionItem ArsonistHasImpostorVision;
public static bool On;
private static Color32 ShadeColor;
public override bool IsEnable => On;
public override void SetupCustomOption()
{
SetupRoleOptions(10400, TabGroup.NeutralRoles, CustomRoles.Arsonist);
ArsonistDouseTime = new FloatOptionItem(10410, "ArsonistDouseTime", new(0f, 90f, 0.5f), 3f, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Arsonist])
.SetValueFormat(OptionFormat.Seconds);
ArsonistCooldown = new FloatOptionItem(10411, "Cooldown", new(0f, 60f, 0.5f), 10f, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Arsonist])
.SetValueFormat(OptionFormat.Seconds);
ArsonistCanIgniteAnytime = new BooleanOptionItem(10413, "ArsonistCanIgniteAnytime", false, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Arsonist]);
ArsonistMinPlayersToIgnite = new IntegerOptionItem(10414, "ArsonistMinPlayersToIgnite", new(1, 14, 1), 1, TabGroup.NeutralRoles)
.SetParent(ArsonistCanIgniteAnytime);
ArsonistMaxPlayersToIgnite = new IntegerOptionItem(10415, "ArsonistMaxPlayersToIgnite", new(1, 14, 1), 3, TabGroup.NeutralRoles)
.SetParent(ArsonistCanIgniteAnytime);
ArsonistKeepsGameGoing = new BooleanOptionItem(10412, "ArsonistKeepsGameGoing", false, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Arsonist]);
ArsonistCanVent = new BooleanOptionItem(10416, "CanVent", false, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Arsonist]);
ArsonistHasImpostorVision = new BooleanOptionItem(10417, "ImpostorVision", false, TabGroup.NeutralRoles)
.SetParent(CustomRoleSpawnChances[CustomRoles.Arsonist]);
}
public override void Add(byte playerId)
{
On = true;
ShadeColor = Utils.GetRoleColor(CustomRoles.Arsonist).ShadeColor(0.25f);
foreach (PlayerControl ar in Main.CachedAllPlayerControls()) IsDoused.Add((playerId, ar.PlayerId), false);
}
public override void Init()
{
On = false;
ArsonistTimer = [];
IsDoused = [];
}
public override bool CanUseKillButton(PlayerControl pc)
{
return ArsonistCanIgniteAnytime.GetBool() || !pc.IsDouseDone();
}
public override bool CanUseImpostorVentButton(PlayerControl pc)
{
return pc.IsDouseDone() || ArsonistCanVent.GetBool() || (ArsonistCanIgniteAnytime.GetBool() && !UsePets.GetBool() && (Utils.GetDousedPlayerCount(pc.PlayerId).Item1 >= ArsonistMinPlayersToIgnite.GetInt() || pc.inVent));
}
public override void SetKillCooldown(byte id)
{
Main.AllPlayerKillCooldown[id] = ArsonistCooldown.GetFloat();
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
{
opt.SetVision(ArsonistHasImpostorVision.GetBool());
}
public override void GetProgressText(byte playerId, bool comms, StringBuilder resultText)
{
(int, int) doused = Utils.GetDousedPlayerCount(playerId);
Color32 color = ShadeColor;
resultText.Append(Utils.ColorPrefix(color))
.Append("<color=#777777>-</color> ")
.Append(doused.Item1)
.Append('/');
resultText.Append(!ArsonistCanIgniteAnytime.GetBool() ? doused.Item2 : ArsonistMaxPlayersToIgnite.GetInt());
resultText.Append("</color>");
}
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
{
float cooldown = ArsonistCooldown.GetFloat();
if (ArsonistCanIgniteAnytime.GetBool() && IsDoused[(killer.PlayerId, target.PlayerId)] && Utils.GetDousedPlayerCount(killer.PlayerId).Doused >= ArsonistMinPlayersToIgnite.GetInt())
{
killer.SetKillCooldown(cooldown);
Ignite(killer.MyPhysics);
return false;
}
float douseTime = ArsonistDouseTime.GetFloat();
killer.SetKillCooldown(Mathf.Approximately(douseTime, 0f) ? cooldown : douseTime);
if (!IsDoused[(killer.PlayerId, target.PlayerId)] && !ArsonistTimer.ContainsKey(killer.PlayerId) && killer.RpcCheckAndMurder(target, check: true))
{
ArsonistTimer.Add(killer.PlayerId, (target, 0f));
Utils.NotifyRoles(SpecifySeer: killer, SpecifyTarget: target, ForceLoop: true);
RPC.SetCurrentDousingTarget(killer.PlayerId, target.PlayerId);
}
return false;
}
public override void OnPet(PlayerControl pc)
{
if (ArsonistCanIgniteAnytime.GetBool()) return;
Ignite(pc.MyPhysics);
}
public override void OnEnterVent(PlayerControl pc, Vent vent)
{
if (ArsonistCanIgniteAnytime.GetBool()) return;
if (UsePets.GetBool()) return;
if (AmongUsClient.Instance.IsGameStarted)
Ignite(pc.MyPhysics);
}
private static void Ignite(PlayerPhysics physics)
{
switch (ArsonistCanIgniteAnytime.GetBool())
{
case false when physics.myPlayer.IsDouseDone():
{
CustomSoundsManager.RPCPlayCustomSoundAll("Boom");
foreach (PlayerControl pc in Main.EnumerateAlivePlayerControls())
{
if (pc != physics.myPlayer)
pc.Suicide(PlayerState.DeathReason.Torched, physics.myPlayer);
}
foreach (PlayerControl pc in Main.EnumeratePlayerControls())
pc.KillFlash();
if (CustomWinnerHolder.WinnerTeam is CustomWinner.Crewmate or CustomWinner.Impostor)
CustomWinnerHolder.Reset();
CustomWinnerHolder.ShiftWinnerAndSetWinner(CustomWinner.Arsonist);
CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId);
return;
}
case true:
{
int douseCount = Utils.GetDousedPlayerCount(physics.myPlayer.PlayerId).Doused;
if (douseCount >= ArsonistMinPlayersToIgnite.GetInt()) // Don't check for max, since the player would not be able to ignite at all if they somehow get more players doused than the max
{
if (douseCount > ArsonistMaxPlayersToIgnite.GetInt()) Logger.Warn("Arsonist Ignited with more players doused than the maximum amount in the settings", "Arsonist Ignite");
foreach (PlayerControl pc in Main.EnumerateAlivePlayerControls())
{
if (!physics.myPlayer.IsDousedPlayer(pc)) continue;
pc.Suicide(PlayerState.DeathReason.Torched, physics.myPlayer);
}
physics.myPlayer.KillFlash();
int apc = Main.AllAlivePlayerControlsCount;
switch (apc)
{
case 1:
CustomWinnerHolder.SetWinnerOrAdditonalWinner(CustomWinner.Arsonist);
CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId);
break;
case 2:
if (Main.EnumerateAlivePlayerControls().Where(x => x.PlayerId != physics.myPlayer.PlayerId).All(x => x.GetCountTypes() == CountTypes.Crew))
{
CustomWinnerHolder.SetWinnerOrAdditonalWinner(CustomWinner.Arsonist);
CustomWinnerHolder.WinnerIds.Add(physics.myPlayer.PlayerId);
}
break;
}
}
break;
}
}
}
public override void OnGlobalFixedUpdate(PlayerControl player, bool lowLoad)
{
byte playerId = player.PlayerId;
if (GameStates.IsInTask && ArsonistTimer.TryGetValue(playerId, out var value))
{
PlayerControl arTarget = value.Player;
if (!player.IsAliveWithConditions())
{
ArsonistTimer.Remove(playerId);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: arTarget, ForceLoop: true);
RPC.ResetCurrentDousingTarget(playerId);
}
else
{
float arTime = value.Timer;
if (!arTarget.IsAlive())
ArsonistTimer.Remove(playerId);
else if (arTime >= ArsonistDouseTime.GetFloat())
{
player.SetKillCooldown();
ArsonistTimer.Remove(playerId);
IsDoused[(playerId, arTarget.PlayerId)] = true;
player.RpcSetDousedPlayer(arTarget, true);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: arTarget, ForceLoop: true);
RPC.ResetCurrentDousingTarget(playerId);
}
else
{
float range = player.GetKillDistance();
if (FastVector2.DistanceWithinRange(player.Pos(), arTarget.Pos(), range))
ArsonistTimer[playerId] = (arTarget, arTime + Time.fixedDeltaTime);
else
{
player.SetKillCooldown(0.01f);
ArsonistTimer.Remove(playerId);
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: arTarget, ForceLoop: true);
RPC.ResetCurrentDousingTarget(playerId);
Logger.Info($"Canceled: {player.GetNameWithRole()}", "Arsonist");
}
}
}
}
}
public override void SetButtonTexts(HudManager hud, byte id)
{
hud.KillButton?.OverrideText(Translator.GetString("ArsonistDouseButtonText"));
ActionButton usedButton = UsePhantomBasis.GetBool() ? hud.AbilityButton : UsePets.GetBool() ? hud.PetButton : hud.ImpostorVentButton;
usedButton?.OverrideText(Translator.GetString("ArsonistVentButtonText"));
}
}