using Content.Shared.Access.Components; using Content.Shared.Interaction; using Content.Shared.Inventory; using Content.Shared.Lock; using Content.Shared.Popups; using Content.Shared.Roles.Jobs; using Content.Shared.StatusIcon; using Content.Shared.VoiceMask; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Access.Systems; /// /// Handles things related to the agent ID, such as copying access and the UI. /// public abstract partial class SharedAgentIdCardSystem : EntitySystem { [Dependency] private LockSystem _lock = default!; [Dependency] private SharedPopupSystem _popup = default!; [Dependency] private SharedIdCardSystem _card = default!; [Dependency] private SharedJobSystem _job = default!; [Dependency] private SharedJobStatusSystem _jobStatus = default!; /// /// Steals access from interacted ids. /// [SubscribeLocalEvent] private void OnAfterInteract(Entity ent, ref AfterInteractEvent args) { if (args.Target == null || !args.CanReach || _lock.IsLocked(ent.Owner) || !TryComp(args.Target, out var targetAccess) || !HasComp(args.Target)) return; // Am I an id? if (!TryComp(ent, out var access) || !HasComp(ent)) return; var beforeLength = access.Tags.Count; access.Tags.UnionWith(targetAccess.Tags); var addedLength = access.Tags.Count - beforeLength; _popup.PopupEntity(Loc.GetString("agent-id-new", ("number", addedLength), ("card", args.Target)), args.Target.Value, args.User); if (addedLength > 0) Dirty(ent, access); } [SubscribeLocalEvent] private void OnVoiceMaskNameChanged(Entity ent, ref InventoryRelayedEvent args) { if (!TryComp(ent, out var idCard)) return; if (!args.Args.VoiceMask.Comp.ChangeIDName) return; _card.TryChangeFullName(ent, args.Args.NewName, idCard); } [SubscribeLocalEvent] private void OnNameChanged(Entity ent, ref AgentIDCardNameChangedMessage args) { if (!_card.TryChangeFullName(ent, args.Name)) return; UpdateUi(ent); } [SubscribeLocalEvent] private void OnJobChanged(Entity ent, ref AgentIDCardJobChangedMessage args) { if (!_card.TryChangeJobTitle(ent, args.Job)) return; UpdateUi(ent); } [SubscribeLocalEvent] private void OnJobIconChanged(Entity ent, ref AgentIDCardJobIconChangedMessage args) { if (!ProtoMan.Resolve(args.JobIconId, out var jobIcon) || !_card.TryChangeJobIcon(ent, jobIcon)) return; if (_job.TryGetJobFromIcon(jobIcon.ID, out var job)) _card.TryChangeJobDepartment(ent, job); _jobStatus.UpdateIdHolderStatus(ent); UpdateUi(ent); } /// /// Update the agent id UI with new component info. /// public virtual void UpdateUi(EntityUid entity) { // Overridden on client } } /// /// Key representing which bound user interface is currently open. /// Useful when there are multiple UI for an object. Here it's future-proofing only. /// [Serializable, NetSerializable] public enum AgentIDCardUiKey : byte { Key, } /// /// Sent from the agent ID UI to change the card name. /// [Serializable, NetSerializable] public sealed class AgentIDCardNameChangedMessage(string name) : BoundUserInterfaceMessage { public string Name { get; } = name; } /// /// Sent from the agent ID UI to change the job title. /// [Serializable, NetSerializable] public sealed class AgentIDCardJobChangedMessage(string job) : BoundUserInterfaceMessage { public string Job { get; } = job; } /// /// Sent from the agent ID UI to change the job icon. /// [Serializable, NetSerializable] public sealed class AgentIDCardJobIconChangedMessage(ProtoId icon) : BoundUserInterfaceMessage { public ProtoId JobIconId { get; } = icon; }