using Content.Server.Ghost.Roles.Components; using Content.Server.Instruments; using Content.Server.Mind.Components; using Content.Server.Popups; using Content.Shared.Examine; using Content.Shared.Interaction.Events; using Content.Shared.PAI; using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Server.GameObjects; namespace Content.Server.PAI { public sealed class PAISystem : SharedPAISystem { [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly InstrumentSystem _instrumentSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent(OnMindAdded); SubscribeLocalEvent(OnMindRemoved); SubscribeLocalEvent>(AddWipeVerb); } private void OnExamined(EntityUid uid, PAIComponent component, ExaminedEvent args) { if (args.IsInDetailsRange) { if (EntityManager.TryGetComponent(uid, out var mind) && mind.HasMind) { args.PushMarkup(Loc.GetString("pai-system-pai-installed")); } else if (EntityManager.HasComponent(uid)) { args.PushMarkup(Loc.GetString("pai-system-still-searching")); } else { args.PushMarkup(Loc.GetString("pai-system-off")); } } } private void OnUseInHand(EntityUid uid, PAIComponent component, UseInHandEvent args) { if (args.Handled) return; // Placeholder PAIs are essentially portable ghost role generators. args.Handled = true; // Check for pAI activation if (EntityManager.TryGetComponent(uid, out var mind) && mind.HasMind) { _popupSystem.PopupEntity(Loc.GetString("pai-system-pai-installed"), uid, args.User, PopupType.Large); return; } else if (EntityManager.HasComponent(uid)) { _popupSystem.PopupEntity(Loc.GetString("pai-system-still-searching"), uid, args.User); return; } // Ownership tag string val = Loc.GetString("pai-system-pai-name", ("owner", args.User)); // TODO Identity? People shouldn't dox-themselves by carrying around a PAI. // But having the pda's name permanently be "old lady's PAI" is weird. // Changing the PAI's identity in a way that ties it to the owner's identity also seems weird. // Cause then you could remotely figure out information about the owner's equipped items. EntityManager.GetComponent(component.Owner).EntityName = val; var ghostRole = EnsureComp(uid); EnsureComp(uid); ghostRole.RoleName = Loc.GetString("pai-system-role-name"); ghostRole.RoleDescription = Loc.GetString("pai-system-role-description"); _popupSystem.PopupEntity(Loc.GetString("pai-system-searching"), uid, args.User); UpdatePAIAppearance(uid, PAIStatus.Searching); } private void OnMindRemoved(EntityUid uid, PAIComponent component, MindRemovedMessage args) { // Mind was removed, shutdown the PAI. PAITurningOff(uid); } private void OnMindAdded(EntityUid uid, PAIComponent pai, MindAddedMessage args) { // Mind was added, shutdown the ghost role stuff so it won't get in the way if (EntityManager.HasComponent(uid)) EntityManager.RemoveComponent(uid); UpdatePAIAppearance(uid, PAIStatus.On); } private void PAITurningOff(EntityUid uid) { UpdatePAIAppearance(uid, PAIStatus.Off); // Close the instrument interface if it was open // before closing if (HasComp(uid) && TryComp(uid, out var actor)) { _instrumentSystem.ToggleInstrumentUi(uid, actor.PlayerSession); } // Stop instrument if (EntityManager.TryGetComponent(uid, out var instrument)) _instrumentSystem.Clean(uid, instrument); if (EntityManager.TryGetComponent(uid, out var metadata)) { var proto = metadata.EntityPrototype; if (proto != null) metadata.EntityName = proto.Name; } } private void UpdatePAIAppearance(EntityUid uid, PAIStatus status) { if (EntityManager.TryGetComponent(uid, out var appearance)) { _appearance.SetData(uid, PAIVisuals.Status, status, appearance); } } private void AddWipeVerb(EntityUid uid, PAIComponent pai, GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract) return; if (EntityManager.TryGetComponent(uid, out var mind) && mind.HasMind) { ActivationVerb verb = new(); verb.Text = Loc.GetString("pai-system-wipe-device-verb-text"); verb.Act = () => { if (pai.Deleted) return; // Wiping device :( // The shutdown of the Mind should cause automatic reset of the pAI during OnMindRemoved // EDIT: But it doesn't!!!! Wtf? Do stuff manually if (EntityManager.HasComponent(uid)) { EntityManager.RemoveComponent(uid); _popupSystem.PopupEntity(Loc.GetString("pai-system-wiped-device"), uid, args.User, PopupType.Large); PAITurningOff(uid); } }; args.Verbs.Add(verb); } else if (EntityManager.HasComponent(uid)) { ActivationVerb verb = new(); verb.Text = Loc.GetString("pai-system-stop-searching-verb-text"); verb.Act = () => { if (pai.Deleted) return; if (EntityManager.HasComponent(uid)) { EntityManager.RemoveComponent(uid); EntityManager.RemoveComponent(uid); _popupSystem.PopupEntity(Loc.GetString("pai-system-stopped-searching"), uid, args.User); PAITurningOff(uid); } }; args.Verbs.Add(verb); } } } }