using System.Drawing; using HintServiceMeow.Core.Enum; using HintServiceMeow.Core.Models.Hints; using HintServiceMeow.Core.Utilities; using LabApi.Events.Arguments.PlayerEvents; using LabApi.Events.Handlers; using LabApi.Features; using LabApi.Features.Console; using LabApi.Features.Wrappers; using PlayerRoles; using PlayerRoles.PlayableScps.Scp079; using PlayerRoles.PlayableScps.Scp096; using PlayerRoles.PlayableScps.Scp3114; using Timer = System.Timers.Timer; using MEC; using PlayerRoles.PlayableScps.Scp049.Zombies; namespace SCPTeamHint; public class Plugin : LabApi.Loader.Features.Plugins.Plugin { private readonly object _hintsLock = new(); private readonly Dictionary _spectatorHints = new(); public override string Name => "SCPTeamHint"; public override string Author => "HoherGeist, Code002Lover"; public override Version Version { get; } = new(1, 0, 0); public override string Description => "Displays information about your SCP Teammates"; public override Version RequiredApiVersion { get; } = new(LabApiProperties.CompiledVersion); public override void Enable() { PlayerEvents.Joined += OnJoin; PlayerEvents.Left += OnLeft; Timing.RunCoroutine(ContinuouslyUpdateHints()); } private IEnumerator ContinuouslyUpdateHints() { while (true) { yield return Timing.WaitForSeconds(1); try { UpdateHints(); } catch (Exception e) { Logger.Error(e); } } // ReSharper disable once IteratorNeverReturns } public override void Disable() { PlayerEvents.Joined -= OnJoin; PlayerEvents.Left -= OnLeft; } private static string CollectHint() { var hintTexts = new List(); foreach (var player in Player.ReadyList.Where(x => !x.IsDummy && (x.IsSCP || x.Role is RoleTypeId.Scp0492))) { var text = $" {player.RoleBase.RoleName} | {player.HumeShield} | {player.Health} | {player.Zone} "; switch (player.RoleBase) { case Scp096Role scp: text += "\n"; scp.SubroutineModule.TryGetSubroutine(out Scp096TargetsTracker tracker); if (!tracker) break; var targetColor = tracker.Targets.Count > 0 ? "red" : "grey"; text += $"Targets: {tracker.Targets.Count}"; break; case Scp3114Role scp3114: text += "\n"; var stolenRole = scp3114.CurIdentity.StolenRole; if (scp3114.Disguised) { text += $" {stolenRole}"; } else { text += " None"; } break; case Scp079Role scp079: text = $" {player.RoleBase.RoleName} | {scp079.CurrentCamera.Room.Zone} "; text += "\n"; scp079.SubroutineModule.TryGetSubroutine(out Scp079AuxManager auxManager); scp079.SubroutineModule.TryGetSubroutine(out Scp079TierManager tierManager); if (!auxManager || !tierManager) break; text += $" AUX: {auxManager.CurrentAuxFloored} / {auxManager.MaxAux} | Level {tierManager.AccessTierLevel}"; break; case ZombieRole: var count = GrowingZombies.GrowingZombies.Instance.ZombieCorpseCount[player]; const string corpseColor = "E68A8A"; text += "\n"; text += $" Corpses eaten: {count}"; break; } hintTexts.Add(text); } return string.Join("\n", hintTexts); } private void UpdateHints() { var hintText = CollectHint(); foreach (var player in Player.ReadyList.Where(x => !x.IsDummy)) { try { UpdateHint(player, hintText); } catch (Exception e) { Logger.Warn("Caught exception while updating hint for player"); Logger.Error(e); } } } private void UpdateHint(Player player, string hintText) { bool isContained; lock (_hintsLock) { isContained = _spectatorHints.ContainsKey(player); } if (!isContained) { CreateHint(player); } if (_spectatorHints == null) return; lock (_hintsLock) { var hint = _spectatorHints[player]; hint.Hide = player.RoleBase.Team != Team.SCPs && player.Role != RoleTypeId.Scp0492 && player.Role != RoleTypeId.Overwatch; if (!hint.Hide) hint.Text = hintText; } } private void OnJoin(PlayerJoinedEventArgs ev) { if (ev.Player.IsDummy || ev.Player.IsHost) return; CreateHint(ev.Player); } private void CreateHint(Player player) { var hint = new Hint { Text = "", Alignment = HintAlignment.Left, YCoordinate = 100, Hide = true }; var playerDisplay = PlayerDisplay.Get(player); playerDisplay.AddHint(hint); lock (_hintsLock) { _spectatorHints[player] = hint; } } private void OnLeft(PlayerLeftEventArgs ev) { if (ev.Player.IsDummy || ev.Player.IsHost) return; lock (_hintsLock) { _spectatorHints.Remove(ev.Player); } } }