security HUD now shows a job icon on entities with a body (#18054)

This commit is contained in:
PrPleGoo
2023-08-01 23:17:03 +02:00
committed by GitHub
parent 9d4c1a254a
commit e083b33aae
11 changed files with 256 additions and 13 deletions

View File

@@ -0,0 +1,117 @@
using Content.Shared.GameTicking;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Robust.Client.GameObjects;
using Robust.Client.Player;
namespace Content.Client.Overlays;
/// <summary>
/// This is a base system to make it easier to enable or disabling UI elements based on whether or not the player has
/// some component, either on their controlled entity on some worn piece of equipment.
/// </summary>
public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
{
[Dependency] private readonly IPlayerManager _player = default!;
protected bool IsActive;
protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<T, ComponentStartup>(OnStartup);
SubscribeLocalEvent<T, ComponentRemove>(OnRemove);
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<T, GotEquippedEvent>(OnCompEquip);
SubscribeLocalEvent<T, GotUnequippedEvent>(OnCompUnequip);
SubscribeLocalEvent<T, RefreshEquipmentHudEvent<T>>(OnRefreshComponentHud);
SubscribeLocalEvent<T, InventoryRelayedEvent<RefreshEquipmentHudEvent<T>>>(OnRefreshEquipmentHud);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
}
private void Update(RefreshEquipmentHudEvent<T> ev)
{
IsActive = true;
UpdateInternal(ev);
}
public void Deactivate()
{
if (!IsActive)
return;
IsActive = false;
DeactivateInternal();
}
protected virtual void UpdateInternal(RefreshEquipmentHudEvent<T> args) { }
protected virtual void DeactivateInternal() { }
private void OnStartup(EntityUid uid, T component, ComponentStartup args)
{
RefreshOverlay(uid);
}
private void OnRemove(EntityUid uid, T component, ComponentRemove args)
{
RefreshOverlay(uid);
}
private void OnPlayerAttached(PlayerAttachedEvent args)
{
RefreshOverlay(args.Entity);
}
private void OnPlayerDetached(PlayerDetachedEvent args)
{
if (_player.LocalPlayer?.ControlledEntity == null)
Deactivate();
}
private void OnCompEquip(EntityUid uid, T component, GotEquippedEvent args)
{
RefreshOverlay(args.Equipee);
}
private void OnCompUnequip(EntityUid uid, T component, GotUnequippedEvent args)
{
RefreshOverlay(args.Equipee);
}
private void OnRoundRestart(RoundRestartCleanupEvent args)
{
Deactivate();
}
protected virtual void OnRefreshEquipmentHud(EntityUid uid, T component, InventoryRelayedEvent<RefreshEquipmentHudEvent<T>> args)
{
args.Args.Active = true;
}
protected virtual void OnRefreshComponentHud(EntityUid uid, T component, RefreshEquipmentHudEvent<T> args)
{
args.Active = true;
}
private void RefreshOverlay(EntityUid uid)
{
if (uid != _player.LocalPlayer?.ControlledEntity)
return;
var ev = new RefreshEquipmentHudEvent<T>(TargetSlots);
RaiseLocalEvent(uid, ev);
if (ev.Active)
Update(ev);
else
Deactivate();
}
}

View File

@@ -0,0 +1,73 @@
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Overlays;
using Content.Shared.PDA;
using Content.Shared.StatusIcon;
using Content.Shared.StatusIcon.Components;
using Robust.Shared.Prototypes;
namespace Content.Client.Overlays;
public sealed class ShowSecurityIconsSystem : EquipmentHudSystem<ShowSecurityIconsComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
[ValidatePrototypeId<StatusIconPrototype>]
private const string JobIconForNoId = "JobIconNoId";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<StatusIconComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
}
private void OnGetStatusIconsEvent(EntityUid uid, StatusIconComponent _, ref GetStatusIconsEvent @event)
{
if (!IsActive || @event.InContainer)
{
return;
}
var healthIcons = DecideSecurityIcon(uid);
@event.StatusIcons.AddRange(healthIcons);
}
private IReadOnlyList<StatusIconPrototype> DecideSecurityIcon(EntityUid uid)
{
var result = new List<StatusIconPrototype>();
var jobIconToGet = JobIconForNoId;
if (_accessReader.FindAccessItemsInventory(uid, out var items))
{
foreach (var item in items)
{
// ID Card
if (TryComp(item, out IdCardComponent? id))
{
jobIconToGet = id.JobIcon;
break;
}
// PDA
if (TryComp(item, out PdaComponent? pda)
&& pda.ContainedId != null
&& TryComp(pda.ContainedId, out id))
{
jobIconToGet = id.JobIcon;
break;
}
}
}
if (_prototypeMan.TryIndex<StatusIconPrototype>(jobIconToGet, out var jobIcon))
result.Add(jobIcon);
else
Log.Error($"Invalid job icon prototype: {jobIcon}");
// Add arrest icons here, WYCI.
return result;
}
}