mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
252 lines
9.2 KiB
C#
252 lines
9.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using AmongUs.GameOptions;
|
|
using EHR.Modules;
|
|
using Hazel;
|
|
using UnityEngine;
|
|
using static EHR.Options;
|
|
using static EHR.Translator;
|
|
|
|
namespace EHR.Roles;
|
|
|
|
public class EvilTracker : RoleBase
|
|
{
|
|
private const int Id = 500;
|
|
private static List<byte> PlayerIdList = [];
|
|
|
|
private static OptionItem OptionCanSeeKillFlash;
|
|
private static OptionItem OptionTargetMode;
|
|
private static OptionItem OptionCanSeeLastRoomInMeeting;
|
|
|
|
private static bool CanSeeKillFlash;
|
|
private static TargetMode CurrentTargetMode;
|
|
private static RoleTypes RoleTypes;
|
|
public static bool CanSeeLastRoomInMeeting;
|
|
private static Color32 ShadeColor;
|
|
|
|
private static readonly string[] TargetModeText =
|
|
[
|
|
"EvilTrackerTargetMode.Never",
|
|
"EvilTrackerTargetMode.OnceInGame",
|
|
"EvilTrackerTargetMode.EveryMeeting",
|
|
"EvilTrackerTargetMode.Always"
|
|
];
|
|
|
|
public bool CanSetTarget;
|
|
|
|
private byte EvilTrackerId;
|
|
public byte Target = byte.MaxValue;
|
|
private byte[] ImpostorsId => Main.EnumerateAlivePlayerControls().Where(x => x.PlayerId != EvilTrackerId && x.Is(CustomRoleTypes.Impostor)).Select(x => x.PlayerId).ToArray();
|
|
|
|
public override bool IsEnable => PlayerIdList.Count > 0;
|
|
|
|
public override void SetupCustomOption()
|
|
{
|
|
SetupRoleOptions(Id, TabGroup.ImpostorRoles, CustomRoles.EvilTracker);
|
|
|
|
OptionCanSeeKillFlash = new BooleanOptionItem(Id + 10, "EvilTrackerCanSeeKillFlash", true, TabGroup.ImpostorRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.EvilTracker]);
|
|
|
|
OptionTargetMode = new StringOptionItem(Id + 11, "EvilTrackerTargetMode", TargetModeText, 2, TabGroup.ImpostorRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.EvilTracker]);
|
|
|
|
OptionCanSeeLastRoomInMeeting = new BooleanOptionItem(Id + 12, "EvilTrackerCanSeeLastRoomInMeeting", true, TabGroup.ImpostorRoles)
|
|
.SetParent(CustomRoleSpawnChances[CustomRoles.EvilTracker]);
|
|
}
|
|
|
|
public override void Init()
|
|
{
|
|
PlayerIdList = [];
|
|
Target = byte.MaxValue;
|
|
CanSetTarget = false;
|
|
EvilTrackerId = byte.MaxValue;
|
|
ShadeColor = Palette.ImpostorRed.ShadeColor(0.5f);
|
|
}
|
|
|
|
public override void Add(byte playerId)
|
|
{
|
|
CanSeeKillFlash = OptionCanSeeKillFlash.GetBool();
|
|
CurrentTargetMode = (TargetMode)OptionTargetMode.GetValue();
|
|
RoleTypes = CurrentTargetMode == TargetMode.Never ? RoleTypes.Impostor : RoleTypes.Shapeshifter;
|
|
CanSeeLastRoomInMeeting = OptionCanSeeLastRoomInMeeting.GetBool();
|
|
|
|
PlayerIdList.Add(playerId);
|
|
Target = byte.MaxValue;
|
|
CanSetTarget = CurrentTargetMode != TargetMode.Never;
|
|
EvilTrackerId = playerId;
|
|
|
|
LateTask.New(() =>
|
|
{
|
|
foreach (byte id in ImpostorsId) TargetArrow.Add(playerId, id);
|
|
}, 3f, log: false);
|
|
}
|
|
|
|
public override void Remove(byte playerId)
|
|
{
|
|
PlayerIdList.Remove(playerId);
|
|
}
|
|
|
|
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
|
|
{
|
|
if (RoleTypes != RoleTypes.Shapeshifter) return;
|
|
|
|
AURoleOptions.ShapeshifterCooldown = CanTarget(playerId) ? 1f : 255f;
|
|
AURoleOptions.ShapeshifterDuration = 1f;
|
|
}
|
|
|
|
public override void SetButtonTexts(HudManager __instance, byte playerId)
|
|
{
|
|
__instance.AbilityButton.ToggleVisible(CanTarget(playerId));
|
|
__instance.AbilityButton.OverrideText(GetString("EvilTrackerChangeButtonText"));
|
|
}
|
|
|
|
private bool CanTarget(byte playerId)
|
|
{
|
|
return !Main.PlayerStates[playerId].IsDead && CanSetTarget;
|
|
}
|
|
|
|
public static bool IsTrackTarget(PlayerControl seer, PlayerControl target)
|
|
{
|
|
return Main.PlayerStates[seer.PlayerId].Role is EvilTracker et
|
|
&& seer.IsAlive() && PlayerIdList.Contains(seer.PlayerId)
|
|
&& target.IsAlive() && seer != target
|
|
&& (target.Is(CustomRoleTypes.Impostor) || et.Target == target.PlayerId);
|
|
}
|
|
|
|
public static void OnAnyoneMurder(PlayerControl killer, PlayerControl target)
|
|
{
|
|
if (CanSeeKillFlash && killer.Is(CustomRoleTypes.Impostor) && killer != target && !PlayerIdList.Contains(killer.PlayerId))
|
|
PlayerIdList.ToValidPlayers().Do(x => x.KillFlash());
|
|
}
|
|
|
|
public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
|
|
{
|
|
if (!CanTarget(shapeshifter.PlayerId) || !shapeshifting) return false;
|
|
|
|
if (target == null || target.Is(CustomRoleTypes.Impostor)) return false;
|
|
|
|
SetTarget(shapeshifter.PlayerId, target.PlayerId);
|
|
Logger.Info($"{shapeshifter.GetNameWithRole()}'s target is now {target.GetNameWithRole()}", "EvilTrackerTarget");
|
|
shapeshifter.MarkDirtySettings();
|
|
Utils.NotifyRoles(SpecifySeer: shapeshifter, SpecifyTarget: target);
|
|
Utils.NotifyRoles(SpecifySeer: target, SpecifyTarget: shapeshifter);
|
|
|
|
return false;
|
|
}
|
|
|
|
public override void AfterMeetingTasks()
|
|
{
|
|
try
|
|
{
|
|
if (CurrentTargetMode == TargetMode.EveryMeeting) SetTarget();
|
|
|
|
foreach (byte playerId in PlayerIdList)
|
|
{
|
|
PlayerControl pc = Utils.GetPlayerById(playerId);
|
|
PlayerControl target = Utils.GetPlayerById(Target);
|
|
|
|
try
|
|
{
|
|
if (!pc.IsAlive() || !target.IsAlive()) SetTarget(playerId);
|
|
}
|
|
catch (NullReferenceException) { }
|
|
|
|
pc?.SyncSettings();
|
|
pc?.RpcResetAbilityCooldown();
|
|
target?.MarkDirtySettings();
|
|
}
|
|
}
|
|
catch (Exception ex) { Logger.Error(ex.ToString(), "EvilTracker.AfterMeetingTasks"); }
|
|
}
|
|
|
|
private void SetTarget(byte trackerId = byte.MaxValue, byte targetId = byte.MaxValue)
|
|
{
|
|
if (trackerId == byte.MaxValue)
|
|
CanSetTarget = true;
|
|
else if (targetId == byte.MaxValue)
|
|
Target = byte.MaxValue;
|
|
else
|
|
{
|
|
Target = targetId;
|
|
if (CurrentTargetMode != TargetMode.Always) CanSetTarget = false;
|
|
|
|
TargetArrow.Add(trackerId, targetId);
|
|
}
|
|
|
|
if (!AmongUsClient.Instance.AmHost) return;
|
|
|
|
if (!Utils.DoRPC) return;
|
|
|
|
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetEvilTrackerTarget, SendOption.Reliable);
|
|
writer.Write(trackerId);
|
|
writer.Write(targetId);
|
|
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
|
}
|
|
|
|
public static void ReceiveRPC(MessageReader reader)
|
|
{
|
|
byte trackerId = reader.ReadByte();
|
|
byte targetId = reader.ReadByte();
|
|
(Main.PlayerStates[trackerId].Role as EvilTracker)?.SetTarget(trackerId, targetId);
|
|
}
|
|
|
|
public override void GetProgressText(byte playerId, bool comms, StringBuilder resultText)
|
|
{
|
|
if (CanTarget(playerId))
|
|
resultText.Append(Utils.ColorPrefix(ShadeColor))
|
|
.Append("◁</color>");
|
|
}
|
|
|
|
public static string GetTargetMark(PlayerControl seer, PlayerControl target)
|
|
{
|
|
return Main.PlayerStates[seer.PlayerId].Role is not EvilTracker et ? string.Empty : et.Target == target.PlayerId ? Utils.ColorString(Palette.ImpostorRed, "◀") : string.Empty;
|
|
}
|
|
|
|
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
|
|
{
|
|
if (meeting || hud) return string.Empty;
|
|
|
|
byte trackerId = target.PlayerId;
|
|
if (seer.PlayerId != trackerId || seer.PlayerId != EvilTrackerId) return string.Empty;
|
|
|
|
byte[] imps = ImpostorsId;
|
|
var sb = new StringBuilder(80);
|
|
|
|
if (imps.Length > 0)
|
|
{
|
|
sb.Append(Utils.ColorPrefix(Utils.GetRoleColor(CustomRoles.Impostor)));
|
|
foreach (byte impostorId in imps) sb.Append(TargetArrow.GetArrows(target, impostorId));
|
|
sb.Append("</color>");
|
|
}
|
|
|
|
if (Target != byte.MaxValue) sb.Append(Utils.ColorString(Color.white, TargetArrow.GetArrows(target, Target)));
|
|
|
|
return sb.ToString();
|
|
}
|
|
|
|
public static string GetArrowAndLastRoom(PlayerControl seer, PlayerControl target)
|
|
{
|
|
string text = Utils.ColorString(Palette.ImpostorRed, TargetArrow.GetArrows(seer, target.PlayerId));
|
|
PlainShipRoom room = Main.PlayerStates[target.PlayerId].LastRoom;
|
|
|
|
if (!room)
|
|
text += Utils.ColorString(Color.gray, "@" + GetString("FailToTrack"));
|
|
else
|
|
text += Utils.ColorString(Palette.ImpostorRed, "@" + GetString(room.RoomId.ToString()));
|
|
|
|
return text;
|
|
}
|
|
|
|
#pragma warning disable IDE0079 // Remove unnecessary suppression
|
|
[SuppressMessage("ReSharper", "UnusedMember.Local")]
|
|
#pragma warning restore IDE0079 // Remove unnecessary suppression
|
|
private enum TargetMode
|
|
{
|
|
Never,
|
|
OnceInGame,
|
|
EveryMeeting,
|
|
Always
|
|
}
|
|
} |