Files
EndlessHostRoles/Roles/Standard/Crewmate/Support/Altruist.cs
T
2026-09-17 18:40:21 +02:00

173 lines
5.9 KiB
C#

using System;
using System.Collections.Generic;
using AmongUs.GameOptions;
using EHR.Modules;
using EHR.Modules.Extensions;
// ReSharper disable ConvertIfStatementToReturnStatement
namespace EHR.Roles;
public class Altruist : RoleBase
{
public static bool On;
private static OptionItem ReviveTime;
private static OptionItem ReviveTargetCanReportTheirOwnBody;
private static OptionItem ReviveTargetsKillerGetsAlert;
private static OptionItem ReviveTargetsKillerGetsArrow;
private static HashSet<byte> RevivedPlayers = [];
private byte AlturistId;
public CountdownTimer ReviveTimer;
private byte ReviveTarget;
private Vector2 ReviveTargetPos;
private bool RevivingMode;
public override bool IsEnable => On;
public override void SetupCustomOption()
{
StartSetup(645850)
.AutoSetupOption(ref ReviveTime, 5, new IntegerValueRule(0, 30, 1), OptionFormat.Seconds)
.AutoSetupOption(ref ReviveTargetCanReportTheirOwnBody, false)
.AutoSetupOption(ref ReviveTargetsKillerGetsAlert, true)
.AutoSetupOption(ref ReviveTargetsKillerGetsArrow, true, overrideParent: ReviveTargetsKillerGetsAlert);
}
public override void Init()
{
On = false;
RevivedPlayers = [];
}
public override void Add(byte playerId)
{
On = true;
RevivingMode = true;
ReviveTarget = byte.MaxValue;
ReviveTimer = null;
AlturistId = playerId;
ReviveTargetPos = Vector2.zero;
RevivedPlayers = [];
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
{
AURoleOptions.EngineerCooldown = 0.1f;
AURoleOptions.EngineerInVentMaxTime = 1f;
}
public static bool OnAnyoneCheckReportDeadBody(PlayerControl reporter, NetworkedPlayerInfo target)
{
if (ReviveTargetCanReportTheirOwnBody.GetBool()) return true;
return !RevivedPlayers.Contains(reporter.PlayerId) || target.PlayerId != reporter.PlayerId;
}
public override bool CheckReportDeadBody(PlayerControl reporter, NetworkedPlayerInfo target, PlayerControl killer)
{
if (!RevivingMode || target.Disconnected || target.Object.IsAlive() || target.Object.Is(CustomRoles.Disregarded)) return true;
RevivingMode = false;
ReviveTarget = target.PlayerId;
ReviveTargetPos = reporter.Pos();
ReviveTimer = new CountdownTimer(ReviveTime.GetInt(), () =>
{
PlayerControl rtg = target.Object;
rtg?.RpcRevive();
rtg?.TP(ReviveTargetPos);
rtg?.Notify(Translator.GetString("RevivedByAltruist"), 15f);
RevivedPlayers.Add(ReviveTarget);
if (killer && ReviveTargetsKillerGetsAlert.GetBool())
{
if (ReviveTargetsKillerGetsArrow.GetBool()) TargetArrow.Add(killer.PlayerId, ReviveTarget);
killer.KillFlash();
killer.Notify(Translator.GetString("AltruistKillerAlert"), 10f);
}
ReviveTimer = null;
ReviveTarget = byte.MaxValue;
ReviveTargetPos = Vector2.zero;
if (reporter.AmOwner && rtg && !rtg.Is(Team.Crewmate))
Achievements.Type.IWishIReported.Complete();
}, onTick: () => Utils.NotifyRoles(SpecifySeer: reporter, SpecifyTarget: reporter), onCanceled: () =>
{
ReviveTimer = null;
ReviveTarget = byte.MaxValue;
ReviveTargetPos = Vector2.zero;
});
PlayerState state = Main.PlayerStates[reporter.PlayerId];
state.deathReason = PlayerState.DeathReason.Sacrifice;
state.RealKiller = (DateTime.Now, target.PlayerId);
state.SetDead();
reporter.RpcExileV2();
Utils.AfterPlayerDeathTasks(reporter);
return false;
}
public static void OnAnyoneDead()
{
try
{
if (!On || !ReviveTargetsKillerGetsArrow.GetBool()) return;
foreach (PlayerControl pc in Main.EnumeratePlayerControls())
{
if (RevivedPlayers.FindFirst(x => x.GetPlayer()?.GetRealKiller()?.PlayerId == pc.PlayerId, out byte revived))
{
PlayerControl revivedPlayer = revived.GetPlayer();
if (!revivedPlayer || !revivedPlayer.IsAlive())
{
TargetArrow.Remove(pc.PlayerId, revived);
if (GameStates.IsMeeting || ExileController.Instance) continue;
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
}
}
}
catch (Exception e) { Utils.ThrowException(e); }
}
public override void OnPet(PlayerControl pc)
{
RevivingMode = !RevivingMode;
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
}
public override void OnEnterVent(PlayerControl pc, Vent vent)
{
if (Options.UsePets.GetBool()) return;
OnPet(pc);
}
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
{
if (seer.PlayerId != target.PlayerId || seer.PlayerId != AlturistId || seer.IsModdedClient() && !hud || meeting) return string.Empty;
if (ReviveTimer != null) return string.Format(Translator.GetString("AltruistSuffixRevive"), (int)Math.Ceiling(ReviveTimer.Remaining.TotalSeconds));
return string.Format(Translator.GetString("AltruistSuffix"), Translator.GetString(RevivingMode ? "AltruistReviveMode" : "AltruistReportMode"));
}
public override bool CanUseVent(PlayerControl pc, int ventId)
{
return !IsThisRole(pc) || pc.Is(CustomRoles.Nimble) || pc.GetClosestVent()?.Id == ventId;
}
public override void ManipulateGameEndCheckCrew(PlayerState playerState, out bool keepGameGoing, out int countsAs)
{
keepGameGoing = ReviveTimer != null;
countsAs = 1;
}
}