using Content.Shared.Examine; using Content.Shared.PAI; using Content.Shared.Verbs; using Content.Shared.Instruments; using Content.Server.Popups; using Content.Server.Instruments; using Content.Server.Ghost.Roles.Components; using Content.Server.Mind.Components; using Robust.Server.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.GameObjects; using Robust.Shared.Localization; using Robust.Shared.Player; using Content.Shared.Actions; using Content.Shared.Interaction.Events; namespace Content.Server.PAI { public sealed class PAISystem : SharedPAISystem { [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly InstrumentSystem _instrumentSystem = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent(OnMindAdded); SubscribeLocalEvent(OnMindRemoved); SubscribeLocalEvent>(AddWipeVerb); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnShutdown); } private void OnStartup(EntityUid uid, PAIComponent component, ComponentStartup args) { if (component.MidiAction != null) _actionsSystem.AddAction(uid, component.MidiAction, null); } private void OnShutdown(EntityUid uid, PAIComponent component, ComponentShutdown args) { if (component.MidiAction != null) _actionsSystem.RemoveAction(uid, component.MidiAction); } 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, Filter.Entities(args.User)); return; } else if (EntityManager.HasComponent(uid)) { _popupSystem.PopupEntity(Loc.GetString("pai-system-still-searching"), uid, Filter.Entities(args.User)); return; } // Ownership tag string val = Loc.GetString("pai-system-pai-name", ("owner", args.User)); EntityManager.GetComponent(component.Owner).EntityName = val; var ghostFinder = EntityManager.EnsureComponent(uid); ghostFinder.RoleName = Loc.GetString("pai-system-role-name"); ghostFinder.RoleDescription = Loc.GetString("pai-system-role-description"); _popupSystem.PopupEntity(Loc.GetString("pai-system-searching"), uid, Filter.Entities(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 (EntityManager.TryGetComponent(uid, out var serverUi)) if (EntityManager.TryGetComponent(uid, out var actor)) if (serverUi.TryGetBoundUserInterface(InstrumentUiKey.Key,out var bui)) bui.Close(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(PAIVisuals.Status, status); } } 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, Filter.Entities(args.User)); 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); _popupSystem.PopupEntity(Loc.GetString("pai-system-stopped-searching"), uid, Filter.Entities(args.User)); PAITurningOff(uid); } }; args.Verbs.Add(verb); } } } }