From 39ca8304c48a27c33a4a39102f0ccf09a6b40a6c Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Sun, 19 Jan 2025 05:23:05 -0500 Subject: [PATCH 01/12] Add everything for psionics except equipment. --- .../Overlays/ShowPsionicsRecordIconsSystem.cs | 32 +++ .../PsionicsRecordsConsoleSystem.cs | 11 + ...sionicsRecordsConsoleBoundUserInterface.cs | 64 +++++ .../PsionicsRecordsConsoleWindow.xaml | 35 +++ .../PsionicsRecordsConsoleWindow.xaml.cs | 256 ++++++++++++++++++ .../IdentityManagement/IdentitySystem.cs | 13 +- .../Systems/PsionicsRecordsConsoleSystem.cs | 234 ++++++++++++++++ .../Systems/PsionicsRecordsSystem.cs | 59 ++++ .../Overlays/ShowPsionicsRecordIconsSystem.cs | 14 + .../Components/PsionicsRecordComponent.cs | 19 ++ Content.Shared/Psionics/PsionicsStatus.cs | 21 ++ .../SharedPsionicsRecordsConsoleComponent.cs | 49 ++++ .../PsionicsRecords/PsionicsRecord.cs | 29 ++ .../PsionicsRecords/PsionicsRecordsUi.cs | 78 ++++++ .../SharedPsionicsRecordsConsoleSystem.cs | 54 ++++ .../StatusIcon/StatusIconPrototype.cs | 16 ++ .../psionics-records/psionics-records.ftl | 37 +++ .../Prototypes/Datasets/psionic-records.yml | 15 + .../Devices/Circuitboards/computer.yml | 11 + .../Machines/Computers/computers.yml | 35 +++ Resources/Prototypes/StatusIcon/psionics.yml | 27 ++ .../Misc/psionics_icons.rsi/hud_abusing.png | Bin 0 -> 178 bytes .../psionics_icons.rsi/hud_registered.png | Bin 0 -> 156 bytes .../Misc/psionics_icons.rsi/hud_suspected.png | Bin 0 -> 146 bytes .../Misc/psionics_icons.rsi/meta.json | 20 ++ .../Machines/computers.rsi/meta.json | 52 +++- .../Machines/computers.rsi/registry.png | Bin 0 -> 3115 bytes 27 files changed, 1175 insertions(+), 6 deletions(-) create mode 100644 Content.Client/Overlays/ShowPsionicsRecordIconsSystem.cs create mode 100644 Content.Client/PsionicsRecords/Components/PsionicsRecordsConsoleSystem.cs create mode 100644 Content.Client/PsionicsRecords/PsionicsRecordsConsoleBoundUserInterface.cs create mode 100644 Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml create mode 100644 Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml.cs create mode 100644 Content.Server/PsionicsRecords/Systems/PsionicsRecordsConsoleSystem.cs create mode 100644 Content.Server/PsionicsRecords/Systems/PsionicsRecordsSystem.cs create mode 100644 Content.Shared/Overlays/ShowPsionicsRecordIconsSystem.cs create mode 100644 Content.Shared/Psionics/Components/PsionicsRecordComponent.cs create mode 100644 Content.Shared/Psionics/PsionicsStatus.cs create mode 100644 Content.Shared/PsionicsRecords/Components/SharedPsionicsRecordsConsoleComponent.cs create mode 100644 Content.Shared/PsionicsRecords/PsionicsRecord.cs create mode 100644 Content.Shared/PsionicsRecords/PsionicsRecordsUi.cs create mode 100644 Content.Shared/PsionicsRecords/Systems/SharedPsionicsRecordsConsoleSystem.cs create mode 100644 Resources/Locale/en-US/psionics-records/psionics-records.ftl create mode 100644 Resources/Prototypes/Datasets/psionic-records.yml create mode 100644 Resources/Prototypes/StatusIcon/psionics.yml create mode 100644 Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_abusing.png create mode 100644 Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_registered.png create mode 100644 Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_suspected.png create mode 100644 Resources/Textures/Interface/Misc/psionics_icons.rsi/meta.json create mode 100644 Resources/Textures/Structures/Machines/computers.rsi/registry.png diff --git a/Content.Client/Overlays/ShowPsionicsRecordIconsSystem.cs b/Content.Client/Overlays/ShowPsionicsRecordIconsSystem.cs new file mode 100644 index 00000000000..26f3407adf7 --- /dev/null +++ b/Content.Client/Overlays/ShowPsionicsRecordIconsSystem.cs @@ -0,0 +1,32 @@ +using Content.Shared.Overlays; +using Content.Shared.Psionics.Components; +using Content.Shared.StatusIcon; +using Content.Shared.StatusIcon.Components; +using Robust.Shared.Prototypes; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Client.Overlays; + +public sealed class ShowPsionicsRecordIconsSystem : EquipmentHudSystem +{ + [Dependency] private readonly IPrototypeManager _prototype = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetStatusIconsEvent); + } + + private void OnGetStatusIconsEvent(EntityUid uid, PsionicsRecordComponent component, ref GetStatusIconsEvent ev) + { + if (!IsActive) + return; + + if (_prototype.TryIndex(component.StatusIcon, out var iconPrototype)) + ev.StatusIcons.Add(iconPrototype); + } +} diff --git a/Content.Client/PsionicsRecords/Components/PsionicsRecordsConsoleSystem.cs b/Content.Client/PsionicsRecords/Components/PsionicsRecordsConsoleSystem.cs new file mode 100644 index 00000000000..8f68e38c86d --- /dev/null +++ b/Content.Client/PsionicsRecords/Components/PsionicsRecordsConsoleSystem.cs @@ -0,0 +1,11 @@ +using Content.Shared.PsionicsRecords.Systems; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Client.PsionicsRecords.Systems; + +public sealed class PsionicsRecordsConsoleSystem : SharedPsionicsRecordsConsoleSystem +{ +} diff --git a/Content.Client/PsionicsRecords/PsionicsRecordsConsoleBoundUserInterface.cs b/Content.Client/PsionicsRecords/PsionicsRecordsConsoleBoundUserInterface.cs new file mode 100644 index 00000000000..3d38f6db648 --- /dev/null +++ b/Content.Client/PsionicsRecords/PsionicsRecordsConsoleBoundUserInterface.cs @@ -0,0 +1,64 @@ +using Content.Shared.Access.Systems; +using Content.Shared.PsionicsRecords; +using Content.Shared.PsionicsRecords.Components; +using Content.Shared.Psionics; +using Content.Shared.StationRecords; +using Robust.Client.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Client.PsionicsRecords; + +public sealed class PsionicsRecordsConsoleBoundUserInterface : BoundUserInterface +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; + private readonly AccessReaderSystem _accessReader; + + private PsionicsRecordsConsoleWindow? _window; + + public PsionicsRecordsConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + { + _accessReader = EntMan.System(); + } + + protected override void Open() + { + base.Open(); + + var comp = EntMan.GetComponent(Owner); + + _window = new(Owner, comp.MaxStringLength, _playerManager, _proto, _random, _accessReader); + _window.OnKeySelected += key => + SendMessage(new SelectStationRecord(key)); + _window.OnFiltersChanged += (type, filterValue) => + SendMessage(new SetStationRecordFilter(type, filterValue)); + _window.OnStatusSelected += status => + SendMessage(new PsionicsRecordChangeStatus(status, null)); + _window.OnDialogConfirmed += (status, reason) => + SendMessage(new PsionicsRecordChangeStatus(status, reason)); + _window.OnClose += Close; + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + + if (state is not PsionicsRecordsConsoleState cast) + return; + + _window?.UpdateState(cast); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _window?.Close(); + } +} diff --git a/Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml b/Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml new file mode 100644 index 00000000000..40a3a58b50b --- /dev/null +++ b/Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml.cs b/Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml.cs new file mode 100644 index 00000000000..2099d0aabe3 --- /dev/null +++ b/Content.Client/PsionicsRecords/PsionicsRecordsConsoleWindow.xaml.cs @@ -0,0 +1,256 @@ +using Content.Client.UserInterface.Controls; +using Content.Shared.Access.Systems; +using Content.Shared.Administration; +using Content.Shared.PsionicsRecords; +using Content.Shared.Dataset; +using Content.Shared.Psionics; +using Content.Shared.StationRecords; +using Robust.Client.AutoGenerated; +using Robust.Client.Player; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Utility; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Client.PsionicsRecords; + +// TODO: dedupe shitcode from general records theres a lot +[GenerateTypedNameReferences] +public sealed partial class PsionicsRecordsConsoleWindow : FancyWindow +{ + private readonly IPlayerManager _player; + private readonly IPrototypeManager _proto; + private readonly IRobustRandom _random; + private readonly AccessReaderSystem _accessReader; + + public readonly EntityUid Console; + + [ValidatePrototypeId] + private const string ReasonPlaceholders = "PsionicsRecordsRecordsPlaceholders"; + + public Action? OnKeySelected; + public Action? OnFiltersChanged; + public Action? OnStatusSelected; + public Action? OnDialogConfirmed; + + private uint _maxLength; + private bool _isPopulating; + private bool _access; + private uint? _selectedKey; + private PsionicsRecord? _selectedRecord; + + private DialogWindow? _reasonDialog; + + private StationRecordFilterType _currentFilterType; + + public PsionicsRecordsConsoleWindow(EntityUid console, uint maxLength, IPlayerManager playerManager, IPrototypeManager prototypeManager, IRobustRandom robustRandom, AccessReaderSystem accessReader) + { + RobustXamlLoader.Load(this); + + Console = console; + _player = playerManager; + _proto = prototypeManager; + _random = robustRandom; + _accessReader = accessReader; + + _maxLength = maxLength; + _currentFilterType = StationRecordFilterType.Name; + + OpenCentered(); + + foreach (var item in Enum.GetValues()) + { + FilterType.AddItem(GetTypeFilterLocals(item), (int) item); + } + + foreach (var status in Enum.GetValues()) + { + AddStatusSelect(status); + } + + OnClose += () => _reasonDialog?.Close(); + + RecordListing.OnItemSelected += args => + { + if (_isPopulating || RecordListing[args.ItemIndex].Metadata is not uint cast) + return; + + OnKeySelected?.Invoke(cast); + }; + + RecordListing.OnItemDeselected += _ => + { + if (!_isPopulating) + OnKeySelected?.Invoke(null); + }; + + FilterType.OnItemSelected += eventArgs => + { + var type = (StationRecordFilterType) eventArgs.Id; + + if (_currentFilterType != type) + { + _currentFilterType = type; + FilterListingOfRecords(FilterText.Text); + } + }; + + FilterText.OnTextEntered += args => + { + FilterListingOfRecords(args.Text); + }; + + StatusOptionButton.OnItemSelected += args => + { + SetStatus((PsionicsStatus) args.Id); + }; + } + + public void UpdateState(PsionicsRecordsConsoleState state) + { + if (state.Filter != null) + { + if (state.Filter.Type != _currentFilterType) + { + _currentFilterType = state.Filter.Type; + } + + if (state.Filter.Value != FilterText.Text) + { + FilterText.Text = state.Filter.Value; + } + } + + _selectedKey = state.SelectedKey; + + FilterType.SelectId((int) _currentFilterType); + + // set up the records listing panel + RecordListing.Clear(); + + var hasRecords = state.RecordListing != null && state.RecordListing.Count > 0; + NoRecords.Visible = !hasRecords; + if (hasRecords) + PopulateRecordListing(state.RecordListing!); + + // set up the selected person's record + var selected = _selectedKey != null; + + PersonContainer.Visible = selected; + RecordUnselected.Visible = !selected; + + _access = _player.LocalSession?.AttachedEntity is {} player + && _accessReader.IsAllowed(player, Console); + + // hide access-required editing parts when no access + var editing = _access && selected; + StatusOptionButton.Disabled = !editing; + + if (state is { PsionicsRecord: not null, StationRecord: not null }) + { + PopulateRecordContainer(state.StationRecord, state.PsionicsRecord); + _selectedRecord = state.PsionicsRecord; + } + else + { + _selectedRecord = null; + } + } + + private void PopulateRecordListing(Dictionary listing) + { + _isPopulating = true; + + foreach (var (key, name) in listing) + { + var item = RecordListing.AddItem(name); + item.Metadata = key; + item.Selected = key == _selectedKey; + } + _isPopulating = false; + + RecordListing.SortItemsByText(); + } + + private void PopulateRecordContainer(GeneralStationRecord stationRecord, PsionicsRecord psionicsRecord) + { + var na = Loc.GetString("generic-not-available-shorthand"); + PersonName.Text = stationRecord.Name; + + StatusOptionButton.SelectId((int) psionicsRecord.Status); + if (psionicsRecord.Reason is {} reason) + { + var message = FormattedMessage.FromMarkup(Loc.GetString("psionics-records-console-wanted-reason")); + message.AddText($": {reason}"); + PsionicsList.SetMessage(message); + PsionicsList.Visible = true; + } + else + { + PsionicsList.Visible = false; + } + } + + private void AddStatusSelect(PsionicsStatus status) + { + var name = Loc.GetString($"psionics-records-status-{status.ToString().ToLower()}"); + StatusOptionButton.AddItem(name, (int) status); + } + + private void FilterListingOfRecords(string text = "") + { + if (!_isPopulating) + { + OnFiltersChanged?.Invoke(_currentFilterType, text); + } + } + + private void SetStatus(PsionicsStatus status) + { + if (status != PsionicsStatus.None) // All statuses should have a reasoning. + { + GetReason(status); + return; + } + + OnStatusSelected?.Invoke(status); + } + + private void GetReason(PsionicsStatus status) + { + if (_reasonDialog != null) + { + _reasonDialog.MoveToFront(); + return; + } + + var field = "reason"; + var title = Loc.GetString("psionics-records-status-" + status.ToString().ToLower()); + var placeholders = _proto.Index(ReasonPlaceholders); + var placeholder = Loc.GetString("psionics-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders.Values))); // just funny it doesn't actually get used + var prompt = Loc.GetString("psionics-records-console-reason"); + var entry = new QuickDialogEntry(field, QuickDialogEntryType.LongText, prompt, placeholder); + var entries = new List() { entry }; + _reasonDialog = new DialogWindow(title, entries); + + _reasonDialog.OnConfirmed += responses => + { + var reason = responses[field]; + if (reason.Length < 1 || reason.Length > _maxLength) + return; + + OnDialogConfirmed?.Invoke(status, reason); + }; + + _reasonDialog.OnClose += () => { _reasonDialog = null; }; + } + + private string GetTypeFilterLocals(StationRecordFilterType type) + { + return Loc.GetString($"psionics-records-{type.ToString().ToLower()}-filter"); + } +} diff --git a/Content.Server/IdentityManagement/IdentitySystem.cs b/Content.Server/IdentityManagement/IdentitySystem.cs index 1a2cdcce511..e2f57b648a4 100644 --- a/Content.Server/IdentityManagement/IdentitySystem.cs +++ b/Content.Server/IdentityManagement/IdentitySystem.cs @@ -1,6 +1,7 @@ using Content.Server.Access.Systems; using Content.Server.Administration.Logs; using Content.Server.CriminalRecords.Systems; +using Content.Server.PsionicsRecords.Systems; using Content.Server.Humanoid; using Content.Shared.Clothing; using Content.Shared.Database; @@ -27,6 +28,7 @@ public sealed class IdentitySystem : SharedIdentitySystem [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!; [Dependency] private readonly CriminalRecordsConsoleSystem _criminalRecordsConsole = default!; + [Dependency] private readonly PsionicsRecordsConsoleSystem _psionicsRecordsConsole = default!; private HashSet _queuedIdentityUpdates = new(); @@ -112,7 +114,7 @@ private void UpdateIdentityInfo(EntityUid uid, IdentityComponent identity) _adminLog.Add(LogType.Identity, LogImpact.Medium, $"{ToPrettyString(uid)} changed identity to {name}"); var identityChangedEvent = new IdentityChangedEvent(uid, ident); RaiseLocalEvent(uid, ref identityChangedEvent); - SetIdentityCriminalIcon(uid); + SetIdentityRecordsIcon(uid); } private string GetIdentityName(EntityUid target, IdentityRepresentation representation) @@ -124,13 +126,14 @@ private string GetIdentityName(EntityUid target, IdentityRepresentation represen } /// - /// When the identity of a person is changed, searches the criminal records to see if the name of the new identity - /// has a record. If the new name has a criminal status attached to it, the person will get the criminal status - /// until they change identity again. + /// When the identity of a person is changed, searches the criminal records and psionics records to see if the name + /// of the new identity has a record. If the new name has a criminal status or psionics status attached to it, the + /// person will get the criminal status and/or psionics status until they change identity again. /// - private void SetIdentityCriminalIcon(EntityUid uid) + private void SetIdentityRecordsIcon(EntityUid uid) { _criminalRecordsConsole.CheckNewIdentity(uid); + _psionicsRecordsConsole.CheckNewIdentity(uid); } /// diff --git a/Content.Server/PsionicsRecords/Systems/PsionicsRecordsConsoleSystem.cs b/Content.Server/PsionicsRecords/Systems/PsionicsRecordsConsoleSystem.cs new file mode 100644 index 00000000000..a847d45ce96 --- /dev/null +++ b/Content.Server/PsionicsRecords/Systems/PsionicsRecordsConsoleSystem.cs @@ -0,0 +1,234 @@ +using Content.Server.Popups; +using Content.Server.Radio.EntitySystems; +using Content.Server.Station.Systems; +using Content.Server.StationRecords; +using Content.Server.StationRecords.Systems; +using Content.Shared.Access.Systems; +using Content.Shared.PsionicsRecords; +using Content.Shared.PsionicsRecords.Components; +using Content.Shared.PsionicsRecords.Systems; +using Content.Shared.Psionics; +using Content.Shared.StationRecords; +using Robust.Server.GameObjects; +using System.Diagnostics.CodeAnalysis; +using Content.Shared.IdentityManagement; +using Content.Shared.Psionics.Components; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Server.PsionicsRecords.Systems; + +/// +/// Handles all UI for Psionics records console +/// +public sealed class PsionicsRecordsConsoleSystem : SharedPsionicsRecordsConsoleSystem +{ + [Dependency] private readonly AccessReaderSystem _access = default!; + [Dependency] private readonly PsionicsRecordsSystem _psionicsRecords = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly RadioSystem _radio = default!; + [Dependency] private readonly SharedIdCardSystem _idCard = default!; + [Dependency] private readonly StationRecordsSystem _stationRecords = default!; + [Dependency] private readonly StationSystem _station = default!; + [Dependency] private readonly UserInterfaceSystem _ui = default!; + + public override void Initialize() + { + SubscribeLocalEvent(UpdateUserInterface); + SubscribeLocalEvent(UpdateUserInterface); + + Subs.BuiEvents(PsionicsRecordsConsoleKey.Key, subs => + { + subs.Event(UpdateUserInterface); + subs.Event(OnKeySelected); + subs.Event(OnFiltersChanged); + subs.Event(OnChangeStatus); + }); + } + + private void UpdateUserInterface(Entity ent, ref T args) + { + // TODO: this is probably wasteful, maybe better to send a message to modify the exact state? + UpdateUserInterface(ent); + } + + private void OnKeySelected(Entity ent, ref SelectStationRecord msg) + { + // no concern of sus client since record retrieval will fail if invalid id is given + ent.Comp.ActiveKey = msg.SelectedKey; + UpdateUserInterface(ent); + } + + private void OnFiltersChanged(Entity ent, ref SetStationRecordFilter msg) + { + if (ent.Comp.Filter == null || + ent.Comp.Filter.Type != msg.Type || ent.Comp.Filter.Value != msg.Value) + { + ent.Comp.Filter = new StationRecordsFilter(msg.Type, msg.Value); + UpdateUserInterface(ent); + } + } + + private void OnChangeStatus(Entity ent, ref PsionicsRecordChangeStatus msg) + { + // prevent malf client violating registered/reason nullability + if (msg.Status == PsionicsStatus.Registered != (msg.Reason != null) && + msg.Status == PsionicsStatus.Suspected != (msg.Reason != null) && + msg.Status == PsionicsStatus.Abusing != (msg.Reason != null)) + return; + + if (!CheckSelected(ent, msg.Actor, out var mob, out var key)) + return; + + if (!_stationRecords.TryGetRecord(key.Value, out var record) || record.Status == msg.Status) + return; + + // validate the reason + string? reason = null; + if (msg.Reason != null) + { + reason = msg.Reason.Trim(); + if (reason.Length < 1 || reason.Length > ent.Comp.MaxStringLength) + return; + } + + var oldStatus = record.Status; + + // will probably never fail given the checks above + _psionicsRecords.TryChangeStatus(key.Value, msg.Status, msg.Reason); + + var name = RecordName(key.Value); + var officer = Loc.GetString("psionics-records-console-unknown-officer"); + + var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(null, mob.Value); + RaiseLocalEvent(tryGetIdentityShortInfoEvent); + if (tryGetIdentityShortInfoEvent.Title != null) + { + officer = tryGetIdentityShortInfoEvent.Title; + } + + (string, object)[] args; + if (reason != null) + args = new (string, object)[] { ("name", name), ("officer", officer), ("reason", reason) }; + else + args = new (string, object)[] { ("name", name), ("officer", officer) }; + + // figure out which radio message to send depending on transition + var statusString = (oldStatus, msg.Status) switch + { + // person has been registered + (_, PsionicsStatus.Registered) => "registered", + // person did something suspicious + (_, PsionicsStatus.Suspected) => "suspected", + // person is abusing + (_, PsionicsStatus.Abusing) => "abusing", + // person is no longer suspicious + (PsionicsStatus.Suspected, PsionicsStatus.None) => "not-suspected", + // person is no longer registered + (PsionicsStatus.Registered, PsionicsStatus.None) => "not-registered", + // person is no longer abusing + (PsionicsStatus.Abusing, PsionicsStatus.None) => "not-abusing", + // this is impossible + _ => "not-wanted" + }; + _radio.SendRadioMessage(ent, Loc.GetString($"psionics-records-console-{statusString}", args), + ent.Comp.RadioChannel, ent); + + UpdateUserInterface(ent); + UpdatePsionicsIdentity(name, msg.Status); + } + + private void UpdateUserInterface(Entity ent) + { + var (uid, console) = ent; + var owningStation = _station.GetOwningStation(uid); + + if (!TryComp(owningStation, out var stationRecords)) + { + _ui.SetUiState(uid, PsionicsRecordsConsoleKey.Key, new PsionicsRecordsConsoleState()); + return; + } + + var listing = _stationRecords.BuildListing((owningStation.Value, stationRecords), console.Filter); + + var state = new PsionicsRecordsConsoleState(listing, console.Filter); + if (console.ActiveKey is { } id) + { + // get records to display when a crewmember is selected + var key = new StationRecordKey(id, owningStation.Value); + _stationRecords.TryGetRecord(key, out state.StationRecord, stationRecords); + _stationRecords.TryGetRecord(key, out state.PsionicsRecord, stationRecords); + state.SelectedKey = id; + } + + _ui.SetUiState(uid, PsionicsRecordsConsoleKey.Key, state); + } + + /// + /// Boilerplate that most actions use, if they require that a record be selected. + /// Obviously shouldn't be used for selecting records. + /// + private bool CheckSelected(Entity ent, EntityUid user, + [NotNullWhen(true)] out EntityUid? mob, [NotNullWhen(true)] out StationRecordKey? key) + { + key = null; + mob = null; + + if (!_access.IsAllowed(user, ent)) + { + _popup.PopupEntity(Loc.GetString("psionics-records-permission-denied"), ent, user); + return false; + } + + if (ent.Comp.ActiveKey is not { } id) + return false; + + // checking the console's station since the user might be off-grid using on-grid console + if (_station.GetOwningStation(ent) is not { } station) + return false; + + key = new StationRecordKey(id, station); + mob = user; + return true; + } + + /// + /// Gets the name from a record, or empty string if this somehow fails. + /// + private string RecordName(StationRecordKey key) + { + if (!_stationRecords.TryGetRecord(key, out var record)) + return ""; + + return record.Name; + } + + /// + /// Checks if the new identity's name has a psionics record attached to it, and gives the entity the icon that + /// belongs to the status if it does. + /// + public void CheckNewIdentity(EntityUid uid) + { + var name = Identity.Name(uid, EntityManager); + var xform = Transform(uid); + + // TODO use the entity's station? Not the station of the map that it happens to currently be on? + var station = _station.GetStationInMap(xform.MapID); + + if (station != null && _stationRecords.GetRecordByName(station.Value, name) is { } id) + { + if (_stationRecords.TryGetRecord(new StationRecordKey(id, station.Value), + out var record)) + { + if (record.Status != PsionicsStatus.None) + { + SetPsionicsIcon(name, record.Status, uid); + return; + } + } + } + RemComp(uid); + } +} diff --git a/Content.Server/PsionicsRecords/Systems/PsionicsRecordsSystem.cs b/Content.Server/PsionicsRecords/Systems/PsionicsRecordsSystem.cs new file mode 100644 index 00000000000..c30851316fa --- /dev/null +++ b/Content.Server/PsionicsRecords/Systems/PsionicsRecordsSystem.cs @@ -0,0 +1,59 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Server.StationRecords.Systems; +using Content.Shared.PsionicsRecords; +using Content.Shared.Psionics; +using Content.Shared.StationRecords; +using Content.Server.GameTicking; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Server.PsionicsRecords.Systems; + +/// +/// Psionics records +/// +/// Psionics Records inherit Station Records' core and add role-playing tools for Epistemics: +/// - Ability to track a person's status (None/Suspected/Registered/Abusing) +/// - See cataloguers' actions in Psionics Records in the radio +/// - See reasons for any action with no need to ask the officer personally +/// +public sealed class PsionicsRecordsSystem : EntitySystem +{ + [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly StationRecordsSystem _stationRecords = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGeneralRecordCreated); + } + + private void OnGeneralRecordCreated(AfterGeneralRecordCreatedEvent ev) + { + _stationRecords.AddRecordEntry(ev.Key, new PsionicsRecord()); + _stationRecords.Synchronize(ev.Key); + } + + /// + /// Tries to change the status of the record found by the StationRecordKey. + /// Reason should only be passed if status is not None. + /// + /// True if the status is changed, false if not + public bool TryChangeStatus(StationRecordKey key, PsionicsStatus status, string? reason) + { + // don't do anything if its the same status + if (!_stationRecords.TryGetRecord(key, out var record) + || status == record.Status) + return false; + + record.Status = status; + record.Reason = reason; + + _stationRecords.Synchronize(key); + + return true; + } +} diff --git a/Content.Shared/Overlays/ShowPsionicsRecordIconsSystem.cs b/Content.Shared/Overlays/ShowPsionicsRecordIconsSystem.cs new file mode 100644 index 00000000000..3562ea08088 --- /dev/null +++ b/Content.Shared/Overlays/ShowPsionicsRecordIconsSystem.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameStates; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Shared.Overlays; + +/// +/// This component allows you to see Psionics record status of mobs. +/// + +[RegisterComponent, NetworkedComponent] +public sealed partial class ShowPsionicsRecordIconsComponent : Component { } diff --git a/Content.Shared/Psionics/Components/PsionicsRecordComponent.cs b/Content.Shared/Psionics/Components/PsionicsRecordComponent.cs new file mode 100644 index 00000000000..5884410ebda --- /dev/null +++ b/Content.Shared/Psionics/Components/PsionicsRecordComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared.StatusIcon; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Shared.Psionics.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class PsionicsRecordComponent : Component +{ + /// + /// The icon that should be displayed based on the psionics status of the entity. + /// + [DataField, AutoNetworkedField] + public ProtoId StatusIcon = "PsionicsIconStatus"; +} diff --git a/Content.Shared/Psionics/PsionicsStatus.cs b/Content.Shared/Psionics/PsionicsStatus.cs new file mode 100644 index 00000000000..59530915763 --- /dev/null +++ b/Content.Shared/Psionics/PsionicsStatus.cs @@ -0,0 +1,21 @@ +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Shared.Psionics; + +/// +/// Status used in Psionics Records. +/// +/// None - the default value +/// Suspected - the person is suspected of having psionics +/// Registered - the person is a registered psionics user +/// Abusing - the person has been caught abusing their psionics +/// +public enum PsionicsStatus : byte +{ + None, + Suspected, + Registered, + Abusing +} diff --git a/Content.Shared/PsionicsRecords/Components/SharedPsionicsRecordsConsoleComponent.cs b/Content.Shared/PsionicsRecords/Components/SharedPsionicsRecordsConsoleComponent.cs new file mode 100644 index 00000000000..e8f38073fe9 --- /dev/null +++ b/Content.Shared/PsionicsRecords/Components/SharedPsionicsRecordsConsoleComponent.cs @@ -0,0 +1,49 @@ +using Content.Shared.PsionicsRecords.Systems; +using Content.Shared.Radio; +using Content.Shared.StationRecords; +using Robust.Shared.Prototypes; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Shared.PsionicsRecords.Components; + +/// +/// A component for Psionics Records Console storing an active station record key and a currently applied filter +/// +[RegisterComponent] +[Access(typeof(SharedPsionicsRecordsConsoleSystem))] +public sealed partial class PsionicsRecordsConsoleComponent : Component +{ + /// + /// Currently active station record key. + /// There is no station parameter as the console uses the current station. + /// + /// + /// TODO: in the future this should be clientside instead of something players can fight over. + /// Client selects a record and tells the server the key it wants records for. + /// Server then sends a state with just the records, not the listing or filter, and the client updates just that. + /// I don't know if it's possible to have multiple bui states right now. + /// + [DataField] + public uint? ActiveKey; + + /// + /// Currently applied filter. + /// + [DataField] + public StationRecordsFilter? Filter; + + /// + /// Channel to send messages to when someone's status gets changed. + /// + [DataField] + public ProtoId RadioChannel = "Science"; + + /// + /// Max length of psionics listing strings. + /// + [DataField] + public uint MaxStringLength = 256; +} diff --git a/Content.Shared/PsionicsRecords/PsionicsRecord.cs b/Content.Shared/PsionicsRecords/PsionicsRecord.cs new file mode 100644 index 00000000000..fd68775e410 --- /dev/null +++ b/Content.Shared/PsionicsRecords/PsionicsRecord.cs @@ -0,0 +1,29 @@ +using Content.Shared.Psionics; +using Robust.Shared.Serialization; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Shared.PsionicsRecords; + +/// +/// Psionics record for a crewmember. +/// Can be viewed and edited in a psionics records console by epistemics. +/// +[Serializable, NetSerializable, DataRecord] +public sealed record PsionicsRecord +{ + /// + /// Status of the person (None, Suspect, Registered, Abusing). + /// + [DataField] + public PsionicsStatus Status = PsionicsStatus.None; + + /// + /// When Status is Anything but none, the reason for it. + /// Should never be set otherwise. + /// + [DataField] + public string? Reason; +} diff --git a/Content.Shared/PsionicsRecords/PsionicsRecordsUi.cs b/Content.Shared/PsionicsRecords/PsionicsRecordsUi.cs new file mode 100644 index 00000000000..0e69f2bb6c0 --- /dev/null +++ b/Content.Shared/PsionicsRecords/PsionicsRecordsUi.cs @@ -0,0 +1,78 @@ +using Content.Shared.Psionics; +using Content.Shared.StationRecords; +using Robust.Shared.Serialization; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Shared.PsionicsRecords; + +[Serializable, NetSerializable] +public enum PsionicsRecordsConsoleKey : byte +{ + Key +} + +/// +/// Psionics records console state. There are a few states: +/// - SelectedKey null, Record null, RecordListing null +/// - The station record database could not be accessed. +/// - SelectedKey null, Record null, RecordListing non-null +/// - Records are populated in the database, or at least the station has +/// the correct component. +/// - SelectedKey non-null, Record null, RecordListing non-null +/// - The selected key does not have a record tied to it. +/// - SelectedKey non-null, Record non-null, RecordListing non-null +/// - The selected key has a record tied to it, and the record has been sent. +/// +/// - there is added new filters and so added new states +/// -SelectedKey null, Record null, RecordListing null, filters non-null +/// the station may have data, but they all did not pass through the filters +/// +/// Other states are erroneous. +/// +[Serializable, NetSerializable] +public sealed class PsionicsRecordsConsoleState : BoundUserInterfaceState +{ + /// + /// Currently selected crewmember record key. + /// + public uint? SelectedKey = null; + + public PsionicsRecord? PsionicsRecord = null; + public GeneralStationRecord? StationRecord = null; + public readonly Dictionary? RecordListing; + public readonly StationRecordsFilter? Filter; + + public PsionicsRecordsConsoleState(Dictionary? recordListing, StationRecordsFilter? newFilter) + { + RecordListing = recordListing; + Filter = newFilter; + } + + /// + /// Default state for opening the console + /// + public PsionicsRecordsConsoleState() : this(null, null) + { + } + + public bool IsEmpty() => SelectedKey == null && StationRecord == null && PsionicsRecord == null && RecordListing == null; +} + +/// +/// Used to change status, respecting the psionics nullability rules in . +/// +[Serializable, NetSerializable] +public sealed class PsionicsRecordChangeStatus : BoundUserInterfaceMessage +{ + public readonly PsionicsStatus Status; + public readonly string? Reason; + + public PsionicsRecordChangeStatus(PsionicsStatus status, string? reason) + { + Status = status; + Reason = reason; + } +} diff --git a/Content.Shared/PsionicsRecords/Systems/SharedPsionicsRecordsConsoleSystem.cs b/Content.Shared/PsionicsRecords/Systems/SharedPsionicsRecordsConsoleSystem.cs new file mode 100644 index 00000000000..21867e65a02 --- /dev/null +++ b/Content.Shared/PsionicsRecords/Systems/SharedPsionicsRecordsConsoleSystem.cs @@ -0,0 +1,54 @@ +using Content.Shared.IdentityManagement; +using Content.Shared.IdentityManagement.Components; +using Content.Shared.Psionics; +using Content.Shared.Psionics.Components; + +/// +/// EVERYTHING HERE IS A MODIFIED VERSION OF CRIMINAL RECORDS +/// + +namespace Content.Shared.PsionicsRecords.Systems; + +public abstract class SharedPsionicsRecordsConsoleSystem : EntitySystem +{ + /// + /// Any entity that has the name of the record that was just changed as their visible name will get their icon + /// updated with the new status, if the record got removed their icon will be removed too. + /// + public void UpdatePsionicsIdentity(string name, PsionicsStatus status) + { + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var identity)) + { + if (!Identity.Name(uid, EntityManager).Equals(name)) + continue; + + if (status == PsionicsStatus.None) + RemComp(uid); + else + SetPsionicsIcon(name, status, uid); + } + } + + /// + /// Decides the icon that should be displayed on the entity based on the psionics status + /// + public void SetPsionicsIcon(string name, PsionicsStatus status, EntityUid characterUid) + { + EnsureComp(characterUid, out var record); + + var previousIcon = record.StatusIcon; + + record.StatusIcon = status switch + { + PsionicsStatus.Suspected => "PsionicsIconSuspected", + PsionicsStatus.Registered => "PsionicsIconRegistered", + PsionicsStatus.Abusing => "PsionicsIconAbusing", + _ => record.StatusIcon + }; + + if (previousIcon != record.StatusIcon) + Dirty(characterUid, record); + } +} diff --git a/Content.Shared/StatusIcon/StatusIconPrototype.cs b/Content.Shared/StatusIcon/StatusIconPrototype.cs index 689bec3882b..a9ec1f7098e 100644 --- a/Content.Shared/StatusIcon/StatusIconPrototype.cs +++ b/Content.Shared/StatusIcon/StatusIconPrototype.cs @@ -163,6 +163,22 @@ public sealed partial class SecurityIconPrototype : StatusIconPrototype, IInheri public bool Abstract { get; } } +/// +/// StatusIcons for showing the psionics status on the epi HUD +/// +[Prototype] +public sealed partial class PsionicsIconPrototype : StatusIconPrototype, IInheritingPrototype +{ + /// + [ParentDataField(typeof(AbstractPrototypeIdArraySerializer))] + public string[]? Parents { get; } + + /// + [NeverPushInheritance] + [AbstractDataField] + public bool Abstract { get; } +} + /// /// StatusIcons for faction membership /// diff --git a/Resources/Locale/en-US/psionics-records/psionics-records.ftl b/Resources/Locale/en-US/psionics-records/psionics-records.ftl new file mode 100644 index 00000000000..fc30f888951 --- /dev/null +++ b/Resources/Locale/en-US/psionics-records/psionics-records.ftl @@ -0,0 +1,37 @@ +psionics-records-console-window-title = Psionics Registry Records +psionics-records-console-records-list-title = Crewmembers +psionics-records-console-select-record-info = Select a record. +psionics-records-console-no-records = No records found! +psionics-records-console-no-record-found = No record was found for the selected person. + +## Status + +psionics-records-console-status = Status +psionics-records-status-none = None +psionics-records-status-registered = Registered +psionics-records-status-suspected = Suspected +psionics-records-status-abusing = Abusing + +psionics-records-console-wanted-reason = [color=gray]Psionics Listed[/color] +psionics-records-console-suspected-reason = [color=gray]Suspected Reason[/color] +psionics-records-console-reason = Reason +psionics-records-console-reason-placeholder = For example: {$placeholder} + +psionics-records-permission-denied = Permission denied + +## Security channel notifications + +psionics-records-console-registered = {$name} is registered by {$officer} with psionics: {$reason}. +psionics-records-console-suspected = {$officer} marked {$name} as suspicious because of: {$reason}. +psionics-records-console-not-suspected = {$name} is no longer a suspect. +psionics-records-console-not-registered = {$name} is no longer registered. +psionics-records-console-abusing = {$officer} marked {$name} as abusing because of: {$reason}. +psionics-records-console-abusing = {$name} is no longer marked abusing. +psionics-records-console-unknown-officer = + +## Filters + +psionics-records-filter-placeholder = Input text and press "Enter" +psionics-records-name-filter = Name +psionics-records-prints-filter = Fingerprints +psionics-records-dna-filter = DNA diff --git a/Resources/Prototypes/Datasets/psionic-records.yml b/Resources/Prototypes/Datasets/psionic-records.yml new file mode 100644 index 00000000000..9333b09831a --- /dev/null +++ b/Resources/Prototypes/Datasets/psionic-records.yml @@ -0,0 +1,15 @@ +# "funny" placeholders of extremely minor/non-crimes for wanted reason dialog +- type: dataset + id: PsionicsRecordsRecordsPlaceholders + values: + - Mindswapped with a rat 2 billion times + - Ascended into the telepathic realm with mind control + - Forced a clown to punch himself + - Forced a mime to speak in owo accent + - Mindcontrolled Captain to say bad words + - Pissed off the Oracle + - Became a Psionic + - Usurped the throne + - Mindswapped the Mantis with a shoe + - Drew stick figures in the Chaplain's bible + - Revived a cockroach diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml index e1fd49972c7..7369c32744d 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml @@ -63,6 +63,17 @@ - type: ComputerBoard prototype: ComputerCriminalRecords +- type: entity + parent: BaseComputerCircuitboard + id: PsionicsRecordsComputerCircuitboard + name: psionics registry computer board + description: A computer printed circuit board for a psionics registry computer. + components: + - type: Sprite + state: cpu_science + - type: ComputerBoard + prototype: ComputerPsionicsRecords + - type: entity parent: BaseComputerCircuitboard id: StationRecordsComputerCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 639fa42d10c..accf5774845 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -361,6 +361,41 @@ guides: - CriminalRecords +- type: entity + parent: BaseComputer + id: ComputerPsionicsRecords + name: psionics registry computer + description: This can be used to check psionics registry records. Only epistemics can modify them. + components: + - type: StationAiWhitelist + - type: PsionicsRecordsConsole + - type: UserInterface + interfaces: + enum.PsionicsRecordsConsoleKey.Key: + type: PsionicsRecordsConsoleBoundUserInterface + - type: ActivatableUI + key: enum.PsionicsRecordsConsoleKey.Key + - type: Sprite + layers: + - map: ["computerLayerBody"] + state: computer + - map: ["computerLayerKeyboard"] + state: generic_keyboard + - map: ["computerLayerScreen"] + state: registry + - map: ["computerLayerKeys"] + state: rd_key + - type: PointLight + radius: 1.5 + energy: 1.6 + color: "#1f8c28" + - type: Computer + board: PsionicsRecordsComputerCircuitboard + - type: AccessReader + access: [["Research"]] + # - type: GuideHelp + # guides: # TODO: Add a guide for Psionics Registry + - type: entity parent: BaseComputer id: ComputerStationRecords diff --git a/Resources/Prototypes/StatusIcon/psionics.yml b/Resources/Prototypes/StatusIcon/psionics.yml new file mode 100644 index 00000000000..67aa622204f --- /dev/null +++ b/Resources/Prototypes/StatusIcon/psionics.yml @@ -0,0 +1,27 @@ +- type: psionicsIcon + id: PsionicsIcon + abstract: true + offset: 1 + locationPreference: Left + isShaded: true + +- type: psionicsIcon + parent: PsionicsIcon + id: PsionicsIconSuspected + icon: + sprite: /Textures/Interface/Misc/psionics_icons.rsi + state: hud_suspected + +- type: psionicsIcon + parent: PsionicsIcon + id: PsionicsIconRegistered + icon: + sprite: /Textures/Interface/Misc/psionics_icons.rsi + state: hud_registered + +- type: psionicsIcon + parent: PsionicsIcon + id: PsionicsIconAbusing + icon: + sprite: /Textures/Interface/Misc/psionics_icons.rsi + state: hud_abusing diff --git a/Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_abusing.png b/Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_abusing.png new file mode 100644 index 0000000000000000000000000000000000000000..dd5b4f48211f33d0b8d02f64477396e8f27c49e6 GIT binary patch literal 178 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|ay(reLnNlQ z_8W3F7znT&e^A{Ndh3a^nAo?M!B0H7!j=iymxxsGEH2o+;$M;R& zCU<=Qw1+XOAxSx}-{3sM4gn3bLz@yCHm|vGX2n9c&9?(`S_B?kTK({QyW8_UXJxi8 av}D*BY5H%G>0xG|y$qhNelF{r5}E+H=0h_8 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_registered.png b/Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_registered.png new file mode 100644 index 0000000000000000000000000000000000000000..aa8e441c0a44a7583c781e9dca10b40b78a64b34 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|!aQ9ZLnNjq zzc738|9k^;iS(EM>4^ym2^KSV%dcMK+^%n6@bFTu*~vyAVBF2L*^`fF`6s@F@CF^u za0X+(SfO4^ym2^KSV%dcMK+^%n6pvXPLwWn)mXEX*BMn6tro4d#$_AS^KPW?%ikqe!qRwygZI>R@7Al0ATa+ zV{YEyNZNShWkK)#BU}y~Akp4OVE~~^j}8DzGsoRreG+n+)WF~UhxO%tmSw<9$c=tp z4pY4d)qqgaqDiO418%z1_5nt~wMvx}Tm5xLPF|hvGA9R@1)GM(q_O+@D87c5!&gRM zJlJH~)ZVO7_%ujuzSGZGq2YVA#?YG>G-AyV&nOOSBcfwi6*2V&@;)~Ah;V0IG~pek zURrI-KX#_@o~2zvK*!yQ9XGnswZ0{!F3~iq``k6%S#vzEh>Z`8nVZ$X(LQxK~`g_g;z$3^VT#Md8|^Tet#z3 zmCn`?PIWO7FgDrliS6rQ0OdRAUTUe+!E9q&hASK)n#IGA-9P7X537UOisL?h3$z$1 z+e_HpJ7j?I=LXI|&;4{~1ljZo{PKBhb|hkx$FD8e3QD^w&{km#1VEIV?VfcR4$$!Kxhn6?m5yR=2Sb8k3GX?(Zy8N#+k4~Vc;!fV72%`901!d9E% zK!VttY2ww$w;`Y#p`;5H$;C||5#q@gsZmC~R`8@)tkM^ew;>{yd~497Nv!<=qc@TC_$S<{L?*Sus0S@NsTLzWle#5B($NkcRZ z)ksFQI4I~cdwY(>xR1*<>G(r`jvmn&HCS4Sq-G*(0{`gbm?pGG(8WMl)4gRP`a2tv zC8FbQXc)^$=A39LXjBwUTj;`E2p=hv@3#52YkZVubEJnv_w zo_p>OAqGc7FJ?qfupNdefDin)lOcV0UX^+Et}3U12(}L$i%F6k+|A zQ|X+_eqv@Ja6sWK67E!Ulm2?ZS<->CT;Tb%)Eh8+O>j1%5!$n+V1@H zomKxwfBwg0U&Y&#zGQx*h4T;I>2$ey^K+vDW^rW5oR5zqc z&7<1ESH?CEq4f9LE_&#{;M>$nwTf5o>H&c1SjiC8=&AX6m0p#*aFc*D*ZyJ-1m4fabGF_ukhia-SHy z;Ij^IC<%5njX7#lOj@p8)&bs^y3{c9H*xEwzSz;|iUSKsl6Wkvq+TG@XSI}w=vc}t zmQ%kRkg(d-yf$iB?u;rH^!qbtMcqJ&^SYej&VRQz2kpzQ=1MZ4D_OK1JimYd&5n+a zc8^Jd8d%1C9bh@ZX*>J8WN1J_8jBA-H5^6-wg)&A#Oy87OLbx1@_JH3iB$#uTxix~ zu&@jT06@3zjbyeT-}96tJlSU=`e?VNJ*l2+H1*tbeX*6Ai$GB|Ivr}}u$vWE9a zimk)Jw6?b6d)yx%NWJIE?R&DTS?TrSiE=9iKXg22eN|H)$kWemem%9%)XeNF$~bDG zHz{JmjkXs<+08AP+tw5^kay7&!->)PdQqilOsb1xsx7$@kd~ZbW0hl7=H^Prvzo6D zI|gr+DLuQus^sl8|wS}I7{=Vw0;#Nq~`VqDj%|YI0y50`0draCk51v6& z0AH^Ys)tBQ z3WK^LSc0nTMZx>)dk)PNYs(x83`jdSbLWd#4R#myI!M@SY1X4Eom~Jn&b$@Jx=m7* zA#eKiT`ufdBM z{qvE|AnPsr^4V{y*Ds+Ogl_LrYe}iuFV+Qw=WFT@qv6j2EVw}%j^ensEj#W*q zS&JH10$@$M?>1e55u8jEBjNJ9{F_|JxuJRxLR}HRBihSqi~FxRTXk-n0OW<4 z8KnnYdfdy2fU8O}SoX`BF>vcJYDyk3R1F<5eEY0DxWIc<-SF+{iHld8nMa-+(b`-6 zlg>2V|1B1YurKDvP_h{c<-R4_PlF0Rrh1!@HL18h{Mdb;HAAP1fhx6TuQ@zfYVHsp zkwjNxR+|r)`wav^^cE}lIP#)ut=XFqu$L7gy9LrE z+o10~+`#h_5{-w!u7V$Xn2$$p`K4w5B<1;2?ViC>DNxT(tbigMO=KtpEp-#~_9xjX zl<`2MFNjyc7E{5ViE1b#%{~tt+IbB0?&3${#hv33m+e4xfPOrmw9YddHE?O#zh_n$ z$Mj^~?)3i1j`iC(joIzwuTrVKkCAz2KM<#kk%_%Wv00z z`ry)85+6!2000l_OLd@}65HL;_?IS_$@?$wGX<9KdlWeFj*yK-kh&WTrXI-UAhtis z!XtYgMq>F|f$qUSyiE?seo|1rrj8Af#+^mO)q@ffN3?||twv=<&`-$ab20g{*I9{j zpA>%kyzjTqA4o>7MuW6L89(a$Az4Wp@w5YiW#(z*+Lc?}36>s$$rxJ2ed`awsH1WK zjF`9dBKN^1+yHnh45G4Y{Or;@eofeeSY%k!h{L@WzIwiBVzkb=&Od4}5bEnEd9^M# zk7xaQ$nFuiwpIv#95MD3%YlD(CLyZBEx(=X-DA5bqJI}imy02D@!n`|T&ET+mCu9H z3|!Vi40LoNa~Q{sIEC@S*RP)lB`(aBA<+Qij!IY=vi_DMIyCh7Mv&Hy?6&{r2A2U- zziL(l67&EsZ!bvNaw6EIMx1B9NZ$a)&=xpJl*D{+A5DK`ltw(-Y0n T7`IvQ?;kks?%_s&1ttFn@2fmQ literal 0 HcmV?d00001 From e9014370eef90e5a19d38c21018c568c40b6d985 Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Sun, 19 Jan 2025 06:04:40 -0500 Subject: [PATCH 02/12] Add glasses (which currently don't work in-game, but they're there). --- .../Entities/Clothing/Eyes/glasses.yml | 19 +++++++++++++ .../Prototypes/Entities/Clothing/Eyes/hud.yml | 20 +++++++++++++- .../Glasses/epiglasses.rsi/equipped-EYES.png | Bin 0 -> 214 bytes .../Eyes/Glasses/epiglasses.rsi/icon.png | Bin 0 -> 259 bytes .../Glasses/epiglasses.rsi/inhand-left.png | Bin 0 -> 221 bytes .../Glasses/epiglasses.rsi/inhand-right.png | Bin 0 -> 216 bytes .../Eyes/Glasses/epiglasses.rsi/meta.json | 26 ++++++++++++++++++ .../Eyes/Hud/epi.rsi/equipped-EYES.png | Bin 0 -> 305 bytes .../Clothing/Eyes/Hud/epi.rsi/icon.png | Bin 0 -> 349 bytes .../Clothing/Eyes/Hud/epi.rsi/inhand-left.png | Bin 0 -> 338 bytes .../Eyes/Hud/epi.rsi/inhand-right.png | Bin 0 -> 371 bytes .../Clothing/Eyes/Hud/epi.rsi/meta.json | 26 ++++++++++++++++++ 12 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/equipped-EYES.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/meta.json create mode 100644 Resources/Textures/Clothing/Eyes/Hud/epi.rsi/equipped-EYES.png create mode 100644 Resources/Textures/Clothing/Eyes/Hud/epi.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Eyes/Hud/epi.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Eyes/Hud/epi.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Eyes/Hud/epi.rsi/meta.json diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index 6231663ac79..1018f8006ea 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -231,6 +231,25 @@ - type: IdentityBlocker coverage: EYES +- type: entity + parent: [ClothingEyesBase, ShowPsionicsIcons] + id: ClothingEyesGlassesEpistemics + name: epi psionics glasses + description: Upgraded sunglasses that provide flash immunity and a epistemics psionics HUD. + components: + - type: Sprite + sprite: Clothing/Eyes/Glasses/epiglasses.rsi + - type: Clothing + sprite: Clothing/Eyes/Glasses/epiglasses.rsi + - type: FlashImmunity + - type: EyeProtection + protectionTime: 5 + - type: Tag + tags: + - WhitelistChameleon + - type: IdentityBlocker + coverage: EYES + - type: entity parent: ClothingEyesGlassesCheapSunglasses id: ClothingEyesGlassesCheapSunglassesAviator diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml index a4ba51b4133..dcf3c02e424 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml @@ -15,6 +15,13 @@ - type: ShowHealthBars - type: ShowHealthIcons +- type: entity + id: ShowPsionicsIcons + abstract: true + categories: [ HideSpawnMenu ] + components: + - type: ShowPsionicsRecordIcons + - type: entity parent: ClothingEyesBase id: ClothingEyesHudDiagnostic @@ -64,6 +71,17 @@ tags: - HudSecurity +- type: entity + parent: [ClothingEyesBase, ShowPsionicsIcons] + id: ClothingEyesHudEpistemics + name: epi psionics hud + description: A heads-up display that scans the humanoids in view and provides accurate data about their psionics records. + components: + - type: Sprite + sprite: Clothing/Eyes/Hud/epi.rsi + - type: Clothing + sprite: Clothing/Eyes/Hud/epi.rsi + - type: entity parent: ClothingEyesBase id: ClothingEyesHudBeer @@ -170,7 +188,7 @@ damageContainers: - Biological - type: ShowHealthIcons - damageContainers: + damageContainers: - Biological - type: entity diff --git a/Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/equipped-EYES.png new file mode 100644 index 0000000000000000000000000000000000000000..1c1f4a830cee185f0ea9b874a094fecc98016e6d GIT binary patch literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|CV09yhE&XX zdut=-p#%Z83--}Z)HZIrcIeP4S)*R-h{%YHxmMjC+bpylRTl^eiQHS=*StHwalHt` zkBHdo&pS@6%luqAPuX5+-TgPqCkakuHU^pr0)G}{o%xuozF^g=tC`gr-G7U&oG;(C z?CjaXaHG#f_rKQepJ!Bj!9g+cT;GAV(JLy=lkCcj)`QJ)!Q5N zC7&o}<*R1>Sdg77(7idcLTBE$o0D#dX1wBh`*~A_+ok0*i}jvFW#2Eo`)2nwl}%+0 zDpP_a+7dT1t0ZrXoTohTYxw2K>+UMly~`I55MXf>V0ge>*PPst`YBWx=n)1_S3j3^ HP6FVqufDT$JoLJ^ P6{O75)z4*}Q$iB}o0wVs literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..1b4867ad28a2898bc38c426e374d4ebbbe3d6dec GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|CV9FzhE&XX zduuoEVFMmkhxZE@Ef}>cbKMo;m3QNgXc*>9gG_Sbu)g}Ge0Q~mbzjOu#Z&vh%eh6#SW?tFjp%&SqW zGk2Z)JY~CC8AJM9ZjeC?3_m6*e_?C0O3F`|Vf=;d-m`jHh6gEn*C*RKmbaAgfmC?9 L`njxgN@xNAeS}nQ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/meta.json new file mode 100644 index 00000000000..663a6be032d --- /dev/null +++ b/Resources/Textures/Clothing/Eyes/Glasses/epiglasses.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Recolored by CerberusWolfie but taken from tgstation at commit https://github.com/tgstation/tgstation/commit/5a73e8f825ff279e82949b9329783a9e3070e2da.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-EYES", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Eyes/Hud/epi.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Hud/epi.rsi/equipped-EYES.png new file mode 100644 index 0000000000000000000000000000000000000000..92d769cebfc2844d0afda5915627bc700285dc7c GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|UVFMYhE&XX zdut}#d7*=xUMiTS+>j+yo9 z>w;BU+B&DCOrjifd^Q-K-ulJz~XzV_zx6dw`+~oPbuhZvw+<~`ZiagE>r+ivulviT&@CrA` ng1_5?W4c!K>{(2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Eyes/Hud/epi.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Hud/epi.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3d0bc5a2140918fc5c1976c3116f6f3927475a5a GIT binary patch literal 349 zcmV-j0iyniP)Px$7fD1xR9J=Wlrc-hFc^j(#UJ2Mj_d{tJRZ+~<>BPEUaJA6l#_wYzKyKK zfa~o6w)zm4Qkt?(({!V4|4KVx#I@E0nQ%JOTLvbdH%|LnM{pTl)uUm^?nMZ|%h|kH zJAFLIZm&|Re*bv;wb9ND{3L#NKZk8NJUVE?78MC)oD*b%0KtS6bO2y{d=0>87&hY7 zq9Q61UiY8bdD^3lb4r%tv%!?8ND#s;1FZ>#JLnU|ijK;nAn2a}zn0L`{O4&KNnVahza^cf88nzG`*x zE|356+veN5^HmE0%>;r5|CqjT@6zF0kj zsc0_U(rxH938>h_chWrZs`UTacTId>wFgcTNe=PKoL(K~8KoLh^>6oQo7FnrqOJ>< zW!|&XZb>-3>BZLlxwo%AV}ZC1ME)tayrq2eH)DP36S-IOg7JW`fRVgM*jAf z2A)E*d5&wH@>+c`=-kdQ`=;V^Va-dsHeE`w2%Ds`{5h{;#F?V*$h@?)T>brz=NKFR zJ|X9napvz^_BVQ0O4lx0qvDx4OY7K;pOcTIizUBVlBwkhG^{k%``4SVSNoSbacsMr zxAkVumG|GbM(F4*`eXNg@7qt`t8C9c|J?l=;y5t*|NRYBx9HfpMJFxO_07+}vWtEF z@Lk;c?fH|xR{gDbSFpD1jnLw?Qsz#+eX&VfuC5Ok)-hyYnEqP!cEW`JU-xBB1)1XM L>gTe~DWM4fXz8Qd literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Eyes/Hud/epi.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Hud/epi.rsi/meta.json new file mode 100644 index 00000000000..920314b00b6 --- /dev/null +++ b/Resources/Textures/Clothing/Eyes/Hud/epi.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Recolored by CerberusWolfie but taken from tgstation at commit https://github.com/tgstation/tgstation/commit/5a73e8f825ff279e82949b9329783a9e3070e2da", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-EYES", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} From 24f77c8a3b67b4adf902e652cc7c2d534e01deaf Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Sun, 19 Jan 2025 17:58:28 -0500 Subject: [PATCH 03/12] Change reason to psionics/reason and make glasses work. --- Content.Shared/Inventory/InventorySystem.Relay.cs | 1 + Resources/Locale/en-US/psionics-records/psionics-records.ftl | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs index 4375f1ab193..6d9523e8511 100644 --- a/Content.Shared/Inventory/InventorySystem.Relay.cs +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -65,6 +65,7 @@ public void InitializeRelay() SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); + SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); diff --git a/Resources/Locale/en-US/psionics-records/psionics-records.ftl b/Resources/Locale/en-US/psionics-records/psionics-records.ftl index fc30f888951..f53224530c0 100644 --- a/Resources/Locale/en-US/psionics-records/psionics-records.ftl +++ b/Resources/Locale/en-US/psionics-records/psionics-records.ftl @@ -14,7 +14,7 @@ psionics-records-status-abusing = Abusing psionics-records-console-wanted-reason = [color=gray]Psionics Listed[/color] psionics-records-console-suspected-reason = [color=gray]Suspected Reason[/color] -psionics-records-console-reason = Reason +psionics-records-console-reason = Psionics/Reason psionics-records-console-reason-placeholder = For example: {$placeholder} psionics-records-permission-denied = Permission denied @@ -26,7 +26,7 @@ psionics-records-console-suspected = {$officer} marked {$name} as suspicious bec psionics-records-console-not-suspected = {$name} is no longer a suspect. psionics-records-console-not-registered = {$name} is no longer registered. psionics-records-console-abusing = {$officer} marked {$name} as abusing because of: {$reason}. -psionics-records-console-abusing = {$name} is no longer marked abusing. +psionics-records-console-not-abusing = {$name} is no longer marked abusing. psionics-records-console-unknown-officer = ## Filters From 8984d1790c4e9ac5a5de0f34c87fab3752a477a6 Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Sun, 19 Jan 2025 18:21:32 -0500 Subject: [PATCH 04/12] Fix the image for abusing. --- .../Misc/psionics_icons.rsi/hud_abusing.png | Bin 178 -> 198 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_abusing.png b/Resources/Textures/Interface/Misc/psionics_icons.rsi/hud_abusing.png index dd5b4f48211f33d0b8d02f64477396e8f27c49e6..02c090efe362f834baf6c9a0d34344d51af438ad 100644 GIT binary patch delta 157 zcmV;O0Al~L0mcE4F@JzbL_t&-m3@yf4uU`wMBgVK=vQTxxQU{vqK~p_w@c;^d-i)9P6eM~x04#daqk&LlzeH=~LuM3Rb2PKXev) zB0+JgV;6>7QkR7fQkTU5i1)JglZf~7ya8H(Vk2&kFwX$E5GXdnvSEO;tkBG;p+>XY rP;7({;L@w%_lHL3yv-c9p*aA#SvCHmHNyh{0000 Date: Sun, 19 Jan 2025 20:33:01 -0500 Subject: [PATCH 05/12] Add cartridge and apply it to Chaplain, Mystagogue, Mantis, and Cataloguer. --- .../Cartridges/PsiWatchEntryControl.xaml | 19 +++++ .../Cartridges/PsiWatchEntryControl.xaml.cs | 25 ++++++ .../CartridgeLoader/Cartridges/PsiWatchUi.cs | 31 +++++++ .../Cartridges/PsiWatchUiFragment.xaml | 13 +++ .../Cartridges/PsiWatchUiFragment.xaml.cs | 29 +++++++ .../Cartridges/PsiWatchCartridgeComponent.cs | 28 +++++++ .../Cartridges/PsiWatchCartridgeSystem.cs | 77 ++++++++++++++++++ .../Cartridges/PsiWatchUiState.cs | 24 ++++++ .../en-US/cartridge-loader/psiwatch.ftl | 5 ++ .../Entities/Objects/Devices/cartridges.yml | 24 +++++- .../Entities/Objects/Devices/pda.yml | 14 ++++ .../Entities/Objects/Devices/pda.yml | 1 + .../Devices/cartridge.rsi/cart-psi.png | Bin 0 -> 321 bytes .../Objects/Devices/cartridge.rsi/meta.json | 7 +- 14 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml create mode 100644 Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml.cs create mode 100644 Content.Client/CartridgeLoader/Cartridges/PsiWatchUi.cs create mode 100644 Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml create mode 100644 Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml.cs create mode 100644 Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeComponent.cs create mode 100644 Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeSystem.cs create mode 100644 Content.Shared/CartridgeLoader/Cartridges/PsiWatchUiState.cs create mode 100644 Resources/Locale/en-US/cartridge-loader/psiwatch.ftl create mode 100644 Resources/Textures/Objects/Devices/cartridge.rsi/cart-psi.png diff --git a/Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml b/Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml new file mode 100644 index 00000000000..9dafac9caea --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml.cs b/Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml.cs new file mode 100644 index 00000000000..0951ba55264 --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/PsiWatchEntryControl.xaml.cs @@ -0,0 +1,25 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +/// +/// ADAPTED FROM SECWATCH - DELTAV +/// + +namespace Content.Client.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class PsiWatchEntryControl : BoxContainer +{ + public PsiWatchEntryControl(PsiWatchEntry entry) + { + RobustXamlLoader.Load(this); + + Status.Text = Loc.GetString($"psionics-records-status-{entry.Status.ToString().ToLower()}"); + Title.Text = Loc.GetString("psi-watch-entry", ("name", entry.Name), ("job", entry.Job)); + + Reason.Text = entry.Reason ?? Loc.GetString("psi-watch-no-reason"); + } +} diff --git a/Content.Client/CartridgeLoader/Cartridges/PsiWatchUi.cs b/Content.Client/CartridgeLoader/Cartridges/PsiWatchUi.cs new file mode 100644 index 00000000000..40eb2f19e43 --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/PsiWatchUi.cs @@ -0,0 +1,31 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.UserInterface; + +/// +/// ADAPTED FROM SECWATCH - DELTAV +/// + +namespace Content.Client.CartridgeLoader.Cartridges; + +public sealed partial class PsiWatchUi : UIFragment +{ + private PsiWatchUiFragment? _fragment; + + public override Control GetUIFragmentRoot() + { + return _fragment!; + } + + public override void Setup(BoundUserInterface ui, EntityUid? owner) + { + _fragment = new PsiWatchUiFragment(); + } + + public override void UpdateState(BoundUserInterfaceState state) + { + if (state is PsiWatchUiState cast) + _fragment?.UpdateState(cast); + } +} diff --git a/Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml b/Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml new file mode 100644 index 00000000000..25181e347b3 --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml @@ -0,0 +1,13 @@ + + + + diff --git a/Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml.cs b/Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml.cs new file mode 100644 index 00000000000..e446581317d --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/PsiWatchUiFragment.xaml.cs @@ -0,0 +1,29 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +/// +/// ADAPTED FROM SECWATCH - DELTAV +/// + +namespace Content.Client.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class PsiWatchUiFragment : BoxContainer +{ + public PsiWatchUiFragment() + { + RobustXamlLoader.Load(this); + } + + public void UpdateState(PsiWatchUiState state) + { + NoEntries.Visible = state.Entries.Count == 0; + Entries.RemoveAllChildren(); + foreach (var entry in state.Entries) + { + Entries.AddChild(new PsiWatchEntryControl(entry)); + } + } +} diff --git a/Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeComponent.cs b/Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeComponent.cs new file mode 100644 index 00000000000..66a8b131d35 --- /dev/null +++ b/Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeComponent.cs @@ -0,0 +1,28 @@ +using Content.Shared.Psionics; + +/// +/// ADAPTED FROM SECWATCH - DELTAV +/// + +namespace Content.Server.CartridgeLoader.Cartridges; + +[RegisterComponent, Access(typeof(PsiWatchCartridgeSystem))] +public sealed partial class PsiWatchCartridgeComponent : Component +{ + /// + /// Only show people with these statuses. + /// + [DataField] + public List Statuses = new() + { + PsionicsStatus.Abusing, + PsionicsStatus.Registered, + PsionicsStatus.Suspected + }; + + /// + /// Station entity thats getting its records checked. + /// + [DataField] + public EntityUid? Station; +} diff --git a/Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeSystem.cs b/Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeSystem.cs new file mode 100644 index 00000000000..c0936e10fdb --- /dev/null +++ b/Content.Server/CartridgeLoader/Cartridges/PsiWatchCartridgeSystem.cs @@ -0,0 +1,77 @@ +using Content.Server.Station.Systems; +using Content.Server.StationRecords; +using Content.Server.StationRecords.Systems; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Content.Shared.PsionicsRecords; +using Content.Shared.StationRecords; + +/// +/// ADAPTED FROM SECWATCH - DELTAV +/// + +namespace Content.Server.CartridgeLoader.Cartridges; + +public sealed class PsiWatchCartridgeSystem : EntitySystem +{ + [Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!; + [Dependency] private readonly StationRecordsSystem _records = default!; + [Dependency] private readonly StationSystem _station = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRecordModified); + + SubscribeLocalEvent(OnUiReady); + } + + private void OnRecordModified(RecordModifiedEvent args) + { + // when a record is modified update the ui of every loaded cartridge tuned to the same station + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var cartridge)) + { + if (cartridge.LoaderUid is not {} loader || comp.Station != args.Station) + continue; + + UpdateUI((uid, comp), loader); + } + } + + private void OnUiReady(Entity ent, ref CartridgeUiReadyEvent args) + { + UpdateUI(ent, args.Loader); + } + + private void UpdateUI(Entity ent, EntityUid loader) + { + // if the loader is on a grid, update the station + // if it is off grid use the cached station + if (_station.GetOwningStation(loader) is {} station) + ent.Comp.Station = station; + + if (!TryComp(ent.Comp.Station, out var records)) + return; + + station = ent.Comp.Station.Value; + + var entries = new List(); + foreach (var (id, criminal) in _records.GetRecordsOfType(station, records)) + { + if (!ent.Comp.Statuses.Contains(criminal.Status)) + continue; + + var key = new StationRecordKey(id, station); + if (!_records.TryGetRecord(key, out var general, records)) + continue; + + var status = criminal.Status; + entries.Add(new PsiWatchEntry(general.Name, general.JobTitle, criminal.Status, criminal.Reason)); + } + + var state = new PsiWatchUiState(entries); + _cartridgeLoader.UpdateCartridgeUiState(loader, state); + } +} diff --git a/Content.Shared/CartridgeLoader/Cartridges/PsiWatchUiState.cs b/Content.Shared/CartridgeLoader/Cartridges/PsiWatchUiState.cs new file mode 100644 index 00000000000..7dae7df5a63 --- /dev/null +++ b/Content.Shared/CartridgeLoader/Cartridges/PsiWatchUiState.cs @@ -0,0 +1,24 @@ +using Content.Shared.Psionics; +using Robust.Shared.Serialization; + +namespace Content.Shared.CartridgeLoader.Cartridges; + +/// +/// Show a list of wanted and suspected people from psionics records. +/// +[Serializable, NetSerializable] +public sealed class PsiWatchUiState : BoundUserInterfaceState +{ + public readonly List Entries; + + public PsiWatchUiState(List entries) + { + Entries = entries; + } +} + +/// +/// Entry for a person who is suspected, registered, or abusing. +/// +[Serializable, NetSerializable] +public record struct PsiWatchEntry(string Name, string Job, PsionicsStatus Status, string? Reason); diff --git a/Resources/Locale/en-US/cartridge-loader/psiwatch.ftl b/Resources/Locale/en-US/cartridge-loader/psiwatch.ftl new file mode 100644 index 00000000000..33df99fd44f --- /dev/null +++ b/Resources/Locale/en-US/cartridge-loader/psiwatch.ftl @@ -0,0 +1,5 @@ +psi-watch-program-name = PsiWatch +psi-watch-title = PsiWatch 1.3 +psi-watch-no-entries = Nobody is registered. Why not enjoy a nice, cold brew? +psi-watch-entry = {$name}, {$job} +psi-watch-no-reason = [ERROR] No reason given? diff --git a/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml index e9108fd341b..d2780fef031 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml @@ -87,7 +87,7 @@ - type: Cartridge programName: log-probe-program-name icon: - sprite: Structures/Doors/Airlocks/Standard/security.rsi + sprite: Structures/Doors/Airlocks/Standard/psiurity.rsi state: closed - type: LogProbeCartridge - type: GuideHelp @@ -131,3 +131,25 @@ sprite: Objects/Devices/gps.rsi state: icon - type: AstroNavCartridge + + +- type: entity + parent: BaseItem + id: PsiWatchCartridge + name: psi watch cartridge + description: A cartridge that tracks the status of currently documented psionics individuals. + components: + - type: Sprite + sprite: Objects/Devices/cartridge.rsi + state: cart-psi + - type: Icon + sprite: Objects/Devices/cartridge.rsi + state: cart-psi + - type: UIFragment + ui: !type:PsiWatchUi + - type: Cartridge + programName: psi-watch-program-name + icon: + sprite: DeltaV/Structures/Machines/glimmer_machines.rsi + state: prober + - type: PsiWatchCartridge diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 21d707c915c..a889d2755d2 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -369,6 +369,14 @@ - type: Icon sprite: DeltaV/Objects/Devices/pda.rsi # DeltaV - Give Chaplain PDA Epistemics colors state: pda-chaplain + - type: CartridgeLoader # Nyanotrasen - Glimmer Monitor + preinstalled: + - CrewManifestCartridge + - NotekeeperCartridge + - NewsReaderCartridge + - GlimmerMonitorCartridge + - NanoChatCartridge # DeltaV + - PsiWatchCartridge - type: entity name: logistics officer PDA # DeltaV - Logistics Department replacing Cargo @@ -500,6 +508,7 @@ - NewsReaderCartridge - GlimmerMonitorCartridge - NanoChatCartridge + - PsiWatchCartridge - type: entity parent: BasePDA @@ -809,6 +818,7 @@ - NewsReaderCartridge - GlimmerMonitorCartridge - NanoChatCartridge # DeltaV + - PsiWatchCartridge - type: entity parent: BasePDA @@ -832,6 +842,7 @@ - NewsReaderCartridge - GlimmerMonitorCartridge - NanoChatCartridge + - PsiWatchCartridge - type: entity parent: BasePDA @@ -1387,6 +1398,9 @@ accentVColor: "#8900c9" - type: Icon state: pda-seniorresearcher + - type: CartridgeLoader + preinstalled: + - PsiWatchCartridge - type: entity parent: BaseMedicalPDA diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml index f2a16126b96..af0eb5f0f53 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Devices/pda.yml @@ -122,3 +122,4 @@ - NewsReaderCartridge - GlimmerMonitorCartridge - NanoChatCartridge + - PsiWatchCartridge diff --git a/Resources/Textures/Objects/Devices/cartridge.rsi/cart-psi.png b/Resources/Textures/Objects/Devices/cartridge.rsi/cart-psi.png new file mode 100644 index 0000000000000000000000000000000000000000..446d937c2a4ac798d53a927b9e6685282bdfbdda GIT binary patch literal 321 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}zdcg})hgfqbf`7!5XbR+=APmb_b0Z0^ld z3F(h|52hugC4Bh(+H1>9pCei=KmS~qxmM$mft``B#*`C940jX_=0AEcnX99WK_`!Y z?#-@;*)drwUoqq`-284}wo=h4#O%q_M@knn1wQ<|ZT>37S>i!La{7enVnpM5iX>4qCjEkDm*xWn!;rspjT`Ut0bUz9-;Bq^tA;HR!r4d|pg^gJc P7z_-au6{1-oD!M<*T9IU literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json b/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json index d5b9a8df884..586070e5007 100644 --- a/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json +++ b/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1cdfb0230cc96d0ba751fa002d04f8aa2f25ad7d and tgstation at tgstation at https://github.com/tgstation/tgstation/commit/0c15d9dbcf0f2beb230eba5d9d889ef2d1945bb8, cart-log made by Skarletto (github), cart-sec made by dieselmohawk (discord), cart-nav, cart-med made by ArchRBX (github)", + "copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1cdfb0230cc96d0ba751fa002d04f8aa2f25ad7d and tgstation at tgstation at https://github.com/tgstation/tgstation/commit/0c15d9dbcf0f2beb230eba5d9d889ef2d1945bb8, cart-log made by Skarletto (github), cart-sec made by dieselmohawk (discord), cart-nav, cart-med made by ArchRBX (github), cart-psi made by CerberusWolfie (github/discord)", "size": { "x": 32, "y": 32 @@ -81,6 +81,9 @@ }, { "name": "cart-med" + }, + { + "name": "cart-psi" } ] -} \ No newline at end of file +} From 2c7534f57a319b466af828716c1b303cc8807be4 Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Sun, 19 Jan 2025 22:11:56 -0500 Subject: [PATCH 06/12] Add Loadouts. --- .../Jobs/Epistemics/cataloger.yml | 14 ++++++---- .../Jobs/Epistemics/chaplain.yml | 14 ++++++---- .../Jobs/Epistemics/mystagogue.yml | 14 ++++++---- .../Jobs/Epistemics/psionicMantis.yml | 14 ++++++---- .../Entities/Objects/Devices/pda.yml | 1 + .../Loadouts/Jobs/Epistemics/cataloger.yml | 27 ++++++++++++++++++ .../Loadouts/Jobs/Epistemics/chaplain.yml | 27 ++++++++++++++++++ .../Loadouts/Jobs/Epistemics/mystagogue.yml | 27 ++++++++++++++++++ .../Jobs/Epistemics/psionicMantis.yml | 28 +++++++++++++++++++ 9 files changed, 146 insertions(+), 20 deletions(-) diff --git a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/cataloger.yml b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/cataloger.yml index 2e53ad71dac..d94c971e836 100644 --- a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/cataloger.yml +++ b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/cataloger.yml @@ -25,11 +25,15 @@ - type: loadout id: LoadoutCatalogerPillCanisterSpaceDrugs -#- type: characterItemGroup -# id: LoadoutCatalogerEyes -# maxItems: 1 -# items: -# +- type: characterItemGroup + id: LoadoutCatalogerEyes + maxItems: 1 + items: + - type: loadout + id: LoadoutCatalogerEyesEpiHUD + - type: loadout + id: LoadoutCatalogerEyesEpiGlasses + #- type: characterItemGroup # id: LoadoutCatalogerGloves # maxItems: 1 diff --git a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/chaplain.yml b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/chaplain.yml index ff3d75be33c..3d44c7211dc 100644 --- a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/chaplain.yml +++ b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/chaplain.yml @@ -29,11 +29,15 @@ - type: loadout id: LoadoutChaplainPillCanisterSpaceDrugs -#- type: characterItemGroup -# id: LoadoutChaplainEyes -# maxItems: 1 -# items: -# +- type: characterItemGroup + id: LoadoutChaplainEyes + maxItems: 1 + items: + - type: loadout + id: LoadoutChaplainEyesEpiHUD + - type: loadout + id: LoadoutChaplainEyesEpiGlasses + #- type: characterItemGroup # id: LoadoutChaplainGloves # maxItems: 1 diff --git a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/mystagogue.yml b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/mystagogue.yml index 7e2fbbe4b6a..7bf929a8853 100644 --- a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/mystagogue.yml +++ b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/mystagogue.yml @@ -31,11 +31,15 @@ - type: loadout id: LoadoutMystagoguePillCanisterSpaceDrugs -#- type: characterItemGroup -# id: LoadoutMystagogueEyes -# maxItems: 1 -# items: -# +- type: characterItemGroup + id: LoadoutMystagogueEyes + maxItems: 1 + items: + - type: loadout + id: LoadoutMystagogueEyesEpiHUD + - type: loadout + id: LoadoutMystagogueEyesEpiGlasses + #- type: characterItemGroup # id: LoadoutMystagogueGloves # maxItems: 1 diff --git a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/psionicMantis.yml b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/psionicMantis.yml index 32660c5f0bf..38bdd91206f 100644 --- a/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/psionicMantis.yml +++ b/Resources/Prototypes/CharacterItemGroups/Jobs/Epistemics/psionicMantis.yml @@ -27,11 +27,15 @@ - type: loadout id: LoadoutPsionicMantisPillCanisterCryptobiolin -#- type: characterItemGroup -# id: LoadoutPsionicMantisEyes -# maxItems: 1 -# items: -# +- type: characterItemGroup + id: LoadoutPsionicMantisEyes + maxItems: 1 + items: + - type: loadout + id: LoadoutPsionicMantisEyesEpiHUD + - type: loadout + id: LoadoutPsionicMantisEyesEpiGlasses + #- type: characterItemGroup # id: LoadoutPsionicMantisGloves # maxItems: 1 diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index a889d2755d2..61ab7705135 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -1023,6 +1023,7 @@ - SecWatchCartridge # DeltaV: SecWatch replaces WantedList - StockTradingCartridge # Delta-V - NanoChatCartridge # DeltaV + - PsiWatchCartridge - type: entity parent: CentcomPDA diff --git a/Resources/Prototypes/Loadouts/Jobs/Epistemics/cataloger.yml b/Resources/Prototypes/Loadouts/Jobs/Epistemics/cataloger.yml index 811ae5e2f0b..4eb0ba6973b 100644 --- a/Resources/Prototypes/Loadouts/Jobs/Epistemics/cataloger.yml +++ b/Resources/Prototypes/Loadouts/Jobs/Epistemics/cataloger.yml @@ -60,6 +60,33 @@ - PillCanisterSpaceDrugs # Eyes +- type: loadout + id: LoadoutCatalogerEyesEpiHUD + category: JobsEpistemicsCataloger + cost: 0 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutCatalogerEquipment + - !type:CharacterJobRequirement + jobs: + - Librarian + items: + - ClothingEyesHudEpistemics + +- type: loadout + id: LoadoutCatalogerEyesEpiGlasses + category: JobsEpistemicsCataloger + cost: 3 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutCatalogerEquipment + - !type:CharacterJobRequirement + jobs: + - Librarian + items: + - ClothingEyesGlassesEpistemics # Gloves diff --git a/Resources/Prototypes/Loadouts/Jobs/Epistemics/chaplain.yml b/Resources/Prototypes/Loadouts/Jobs/Epistemics/chaplain.yml index 970d697014f..7a4527cd7a5 100644 --- a/Resources/Prototypes/Loadouts/Jobs/Epistemics/chaplain.yml +++ b/Resources/Prototypes/Loadouts/Jobs/Epistemics/chaplain.yml @@ -75,6 +75,33 @@ - PillCanisterSpaceDrugs # Eyes +- type: loadout + id: LoadoutChaplainEyesEpiHUD + category: JobsEpistemicsChaplain + cost: 0 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutChaplainEquipment + - !type:CharacterJobRequirement + jobs: + - Chaplain + items: + - ClothingEyesHudEpistemics + +- type: loadout + id: LoadoutChaplainEyesEpiGlasses + category: JobsEpistemicsChaplain + cost: 3 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutChaplainEquipment + - !type:CharacterJobRequirement + jobs: + - Chaplain + items: + - ClothingEyesGlassesEpistemics # Gloves diff --git a/Resources/Prototypes/Loadouts/Jobs/Epistemics/mystagogue.yml b/Resources/Prototypes/Loadouts/Jobs/Epistemics/mystagogue.yml index f36ca4f6603..eaa7821a17f 100644 --- a/Resources/Prototypes/Loadouts/Jobs/Epistemics/mystagogue.yml +++ b/Resources/Prototypes/Loadouts/Jobs/Epistemics/mystagogue.yml @@ -88,6 +88,33 @@ - PillCanisterSpaceDrugs # Eyes +- type: loadout + id: LoadoutMystagogueEyesEpiHUD + category: JobsEpistemicsMystagogue + cost: 0 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutMystagogueEquipment + - !type:CharacterJobRequirement + jobs: + - ResearchDirector + items: + - ClothingEyesHudEpistemics + +- type: loadout + id: LoadoutMystagogueEyesEpiGlasses + category: JobsEpistemicsMystagogue + cost: 0 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutMystagogueEquipment + - !type:CharacterJobRequirement + jobs: + - ResearchDirector + items: + - ClothingEyesGlassesEpistemics # Gloves diff --git a/Resources/Prototypes/Loadouts/Jobs/Epistemics/psionicMantis.yml b/Resources/Prototypes/Loadouts/Jobs/Epistemics/psionicMantis.yml index 6df1d8ef1ff..d5f731c9480 100644 --- a/Resources/Prototypes/Loadouts/Jobs/Epistemics/psionicMantis.yml +++ b/Resources/Prototypes/Loadouts/Jobs/Epistemics/psionicMantis.yml @@ -61,6 +61,34 @@ - PillCanisterCryptobiolin # Eyes +- type: loadout + id: LoadoutPsionicMantisEyesEpiHUD + category: JobsEpistemicsPsionicMantis + cost: 0 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutPsionicMantisEquipment + - !type:CharacterJobRequirement + jobs: + - ForensicMantis + items: + - ClothingEyesHudEpistemics + +- type: loadout + id: LoadoutPsionicMantisEyesEpiGlasses + category: JobsEpistemicsPsionicMantis + cost: 3 + exclusive: true + requirements: + - !type:CharacterItemGroupRequirement + group: LoadoutPsionicMantisEquipment + - !type:CharacterJobRequirement + jobs: + - ForensicMantis + items: + - ClothingEyesGlassesEpistemics + # Gloves From 1b81d2a7a6081aa778126a85f25badc7e192fa30 Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Sun, 19 Jan 2025 22:14:54 -0500 Subject: [PATCH 07/12] Add cartridge to locker. --- Resources/Prototypes/Catalog/Fills/Lockers/heads.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml index e57c4166319..9fdae7f6f6b 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml @@ -242,6 +242,7 @@ - id: Intellicard - id: LunchboxCommandFilledRandom # Delta-V Lunchboxes! prob: 0.3 + - id: PsiWatchCartridge - type: entity id: LockerResearchDirectorFilled @@ -264,6 +265,7 @@ - id: EncryptionKeyBinary - id: LunchboxCommandFilledRandom # Delta-V Lunchboxes! prob: 0.3 + - id: PsiWatchCartridge - type: entity id: LockerHeadOfSecurityFilledHardsuit From b78c20b53cbc7db8490fe23591925b9af24afd89 Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Mon, 20 Jan 2025 01:03:34 -0500 Subject: [PATCH 08/12] Change the accesses required to only Chapel, Library, Mantis, and Mystagogue. --- .../Entities/Structures/Machines/Computers/computers.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index accf5774845..d35b02a809d 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -392,7 +392,11 @@ - type: Computer board: PsionicsRecordsComputerCircuitboard - type: AccessReader - access: [["Research"]] + access: + - [ Chapel ] + - [ Library ] + - [ Mantis ] + - [ ResearchDirector ] # - type: GuideHelp # guides: # TODO: Add a guide for Psionics Registry From 4bbdc6f1908464502ae2994307bb8c34d1677f19 Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Mon, 20 Jan 2025 01:03:41 -0500 Subject: [PATCH 09/12] Map on all maps. --- Resources/Maps/arena.yml | 8 +++++ Resources/Maps/asterisk.yml | 8 +++++ Resources/Maps/core.yml | 7 ++++ Resources/Maps/edge.yml | 68 ++++++++++++++++++++++++++++------- Resources/Maps/europa.yml | 16 +++++---- Resources/Maps/gaxstation.yml | 10 +++++- Resources/Maps/glacier.yml | 8 +++++ Resources/Maps/hammurabi.yml | 8 +++++ Resources/Maps/hive.yml | 8 +++++ Resources/Maps/lighthouse.yml | 7 ++++ Resources/Maps/meta.yml | 12 +++++-- Resources/Maps/pebble.yml | 8 +++++ Resources/Maps/radstation.yml | 12 +++++-- Resources/Maps/saltern.yml | 10 +++++- Resources/Maps/shoukou.yml | 10 +++++- Resources/Maps/submarine.yml | 8 +++++ Resources/Maps/tortuga.yml | 8 +++++ 17 files changed, 189 insertions(+), 27 deletions(-) diff --git a/Resources/Maps/arena.yml b/Resources/Maps/arena.yml index aa61c9bb3af..be3a8428849 100644 --- a/Resources/Maps/arena.yml +++ b/Resources/Maps/arena.yml @@ -58311,6 +58311,14 @@ entities: rot: 1.5707963267948966 rad pos: 50.5,7.5 parent: 6747 +- proto: ComputerPsionicsRecords + entities: + - uid: 27824 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 22.5,-62.5 + parent: 6747 - proto: ComputerRadar entities: - uid: 3976 diff --git a/Resources/Maps/asterisk.yml b/Resources/Maps/asterisk.yml index 41fc0f2e73d..4966832b241 100644 --- a/Resources/Maps/asterisk.yml +++ b/Resources/Maps/asterisk.yml @@ -25465,6 +25465,14 @@ entities: rot: 3.141592653589793 rad pos: 30.5,6.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 11188 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -28.5,-18.5 + parent: 2 - proto: ComputerRadar entities: - uid: 10761 diff --git a/Resources/Maps/core.yml b/Resources/Maps/core.yml index 9685efd2e13..8284ed39610 100644 --- a/Resources/Maps/core.yml +++ b/Resources/Maps/core.yml @@ -61680,6 +61680,13 @@ entities: - type: Transform pos: -1.5,-11.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 22546 + components: + - type: Transform + pos: 60.5,-11.5 + parent: 2 - proto: ComputerRadar entities: - uid: 4074 diff --git a/Resources/Maps/edge.yml b/Resources/Maps/edge.yml index f19c2065af2..4c1274f61d1 100644 --- a/Resources/Maps/edge.yml +++ b/Resources/Maps/edge.yml @@ -5356,7 +5356,8 @@ entities: -12,7: 0: 65535 -11,7: - 0: 65535 + 0: 57343 + 3: 8192 -11,-8: 0: 53198 -10,-8: @@ -5451,11 +5452,11 @@ entities: 0: 65535 1,-12: 0: 61937 - 3: 14 - 4: 3584 + 4: 14 + 5: 3584 1,-11: 0: 65521 - 5: 14 + 6: 14 1,-10: 0: 65535 2,-12: @@ -5560,15 +5561,15 @@ entities: 0: 63487 0,-14: 0: 65522 - 3: 12 + 4: 12 0,-13: 0: 65535 1,-14: 0: 65521 1,-13: 0: 61937 - 3: 14 - 6: 3584 + 4: 14 + 7: 3584 2,-14: 0: 12848 2,-13: @@ -5937,7 +5938,7 @@ entities: 0: 1908 -16,7: 0: 40704 - 3: 24576 + 4: 24576 -15,7: 0: 65280 -12,10: @@ -5954,7 +5955,7 @@ entities: 0: 65535 -16,9: 0: 65439 - 3: 96 + 4: 96 -16,10: 0: 231 -15,8: @@ -6091,17 +6092,17 @@ entities: 0: 4095 5,-12: 0: 883 - 3: 3212 + 4: 3212 3,-13: 0: 51200 4,-13: 0: 65392 - 3: 128 + 4: 128 5,-13: 0: 4096 - 3: 59184 + 4: 59184 6,-12: - 3: 305 + 4: 305 uniqueMixes: - volume: 2500 temperature: 293.15 @@ -6148,6 +6149,21 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.14975 + moles: + - 20.078888 + - 75.53487 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - volume: 2500 temperature: 293.15 moles: @@ -39459,6 +39475,14 @@ entities: rot: -1.5707963267948966 rad pos: 0.5,-25.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 17482 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -42.5,32.5 + parent: 2 - proto: ComputerRadar entities: - uid: 6157 @@ -40235,6 +40259,24 @@ entities: - type: Transform pos: -42.5,31.5 parent: 2 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - proto: CrateScienceSecure entities: - uid: 6273 diff --git a/Resources/Maps/europa.yml b/Resources/Maps/europa.yml index 0d54891dc6a..c642efb66c9 100644 --- a/Resources/Maps/europa.yml +++ b/Resources/Maps/europa.yml @@ -34896,12 +34896,6 @@ entities: rot: 1.5707963267948966 rad pos: 6.5,33.5 parent: 1 - - uid: 299 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,17.5 - parent: 1 - uid: 455 components: - type: Transform @@ -37855,6 +37849,14 @@ entities: rot: 3.141592653589793 rad pos: -19.5,-24.5 parent: 1 +- proto: ComputerPsionicsRecords + entities: + - uid: 299 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,17.5 + parent: 1 - proto: ComputerRadar entities: - uid: 3026 @@ -65764,7 +65766,7 @@ entities: pos: -11.5,11.5 parent: 1 - type: Door - secondsUntilStateChange: -26515.367 + secondsUntilStateChange: -27843.273 state: Opening - type: Occluder enabled: True diff --git a/Resources/Maps/gaxstation.yml b/Resources/Maps/gaxstation.yml index f502c4b698d..cada7f3a9d0 100644 --- a/Resources/Maps/gaxstation.yml +++ b/Resources/Maps/gaxstation.yml @@ -53573,6 +53573,14 @@ entities: - type: Transform pos: -31.5,29.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 20872 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 50.5,26.5 + parent: 2 - proto: ComputerRadar entities: - uid: 7211 @@ -134450,7 +134458,7 @@ entities: lastSignals: DoorStatus: True - type: Door - secondsUntilStateChange: -120542.65 + secondsUntilStateChange: -120749.305 state: Opening - uid: 18112 components: diff --git a/Resources/Maps/glacier.yml b/Resources/Maps/glacier.yml index c0fcbe15321..437e8ede164 100644 --- a/Resources/Maps/glacier.yml +++ b/Resources/Maps/glacier.yml @@ -46640,6 +46640,14 @@ entities: - type: Transform pos: 35.5,50.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 17501 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 29.5,-21.5 + parent: 2 - proto: ComputerRadar entities: - uid: 17129 diff --git a/Resources/Maps/hammurabi.yml b/Resources/Maps/hammurabi.yml index 09f874f94b9..d360afe201c 100644 --- a/Resources/Maps/hammurabi.yml +++ b/Resources/Maps/hammurabi.yml @@ -88000,6 +88000,14 @@ entities: rot: 3.141592653589793 rad pos: -114.5,-89.5 parent: 1 +- proto: ComputerPsionicsRecords + entities: + - uid: 42455 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -19.5,-41.5 + parent: 1 - proto: ComputerRadar entities: - uid: 8226 diff --git a/Resources/Maps/hive.yml b/Resources/Maps/hive.yml index ef0019b3454..d24bf87ea5e 100644 --- a/Resources/Maps/hive.yml +++ b/Resources/Maps/hive.yml @@ -60757,6 +60757,14 @@ entities: - type: Transform pos: -96.5,5.5 parent: 1 +- proto: ComputerPsionicsRecords + entities: + - uid: 27792 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,42.5 + parent: 1 - proto: ComputerRadar entities: - uid: 5888 diff --git a/Resources/Maps/lighthouse.yml b/Resources/Maps/lighthouse.yml index 9921bbb9f6d..0ee3064aba6 100644 --- a/Resources/Maps/lighthouse.yml +++ b/Resources/Maps/lighthouse.yml @@ -44908,6 +44908,13 @@ entities: - type: Transform pos: -7.5,-39.5 parent: 100 +- proto: ComputerPsionicsRecords + entities: + - uid: 20901 + components: + - type: Transform + pos: -21.5,-6.5 + parent: 100 - proto: ComputerResearchAndDevelopment entities: - uid: 5793 diff --git a/Resources/Maps/meta.yml b/Resources/Maps/meta.yml index ddbd71d9b11..9e846105d40 100644 --- a/Resources/Maps/meta.yml +++ b/Resources/Maps/meta.yml @@ -10339,7 +10339,7 @@ entities: pos: -53.5,-12.5 parent: 2 - type: Door - secondsUntilStateChange: -12876.496 + secondsUntilStateChange: -13237.977 state: Opening - type: DeviceLinkSource lastSignals: @@ -63773,6 +63773,14 @@ entities: rot: 3.141592653589793 rad pos: 110.5,-0.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 27708 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,-25.5 + parent: 2 - proto: ComputerRadar entities: - uid: 10045 @@ -75704,7 +75712,7 @@ entities: pos: -3.5,-52.5 parent: 2 - type: Door - secondsUntilStateChange: -40902.03 + secondsUntilStateChange: -41263.51 state: Closing - uid: 11944 components: diff --git a/Resources/Maps/pebble.yml b/Resources/Maps/pebble.yml index 9b7c428b513..1d468237f28 100644 --- a/Resources/Maps/pebble.yml +++ b/Resources/Maps/pebble.yml @@ -29532,6 +29532,14 @@ entities: rot: 3.141592653589793 rad pos: 37.5,14.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 10854 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,28.5 + parent: 2 - proto: ComputerRadar entities: - uid: 4588 diff --git a/Resources/Maps/radstation.yml b/Resources/Maps/radstation.yml index f350c67478e..ed00efa981c 100644 --- a/Resources/Maps/radstation.yml +++ b/Resources/Maps/radstation.yml @@ -15129,7 +15129,7 @@ entities: pos: 34.5,-35.5 parent: 2 - type: Door - secondsUntilStateChange: -55586.55 + secondsUntilStateChange: -55771.664 state: Opening - uid: 383 components: @@ -62312,6 +62312,14 @@ entities: - type: Transform pos: -12.5,-55.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 22318 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -5.5,-28.5 + parent: 2 - proto: ComputerRadar entities: - uid: 9048 @@ -157782,7 +157790,7 @@ entities: links: - 19976 - type: Door - secondsUntilStateChange: -191878.86 + secondsUntilStateChange: -192063.97 state: Opening - uid: 23356 components: diff --git a/Resources/Maps/saltern.yml b/Resources/Maps/saltern.yml index e2f8a808534..b681e6923da 100644 --- a/Resources/Maps/saltern.yml +++ b/Resources/Maps/saltern.yml @@ -4332,7 +4332,7 @@ entities: pos: 3.5,22.5 parent: 31 - type: Door - secondsUntilStateChange: -32634.607 + secondsUntilStateChange: -32743.814 state: Opening - type: DeviceLinkSource lastSignals: @@ -29782,6 +29782,14 @@ entities: rot: -1.5707963267948966 rad pos: 60.5,3.5 parent: 31 +- proto: ComputerPsionicsRecords + entities: + - uid: 11412 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -14.5,-22.5 + parent: 31 - proto: ComputerRadar entities: - uid: 579 diff --git a/Resources/Maps/shoukou.yml b/Resources/Maps/shoukou.yml index 4cbe47174af..d75e9c6c75b 100644 --- a/Resources/Maps/shoukou.yml +++ b/Resources/Maps/shoukou.yml @@ -30445,6 +30445,14 @@ entities: rot: 1.5707963267948966 rad pos: 42.5,-35.5 parent: 34 +- proto: ComputerPsionicsRecords + entities: + - uid: 13763 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -30.5,-11.5 + parent: 34 - proto: ComputerRadar entities: - uid: 5579 @@ -36708,7 +36716,7 @@ entities: pos: -36.5,-22.5 parent: 34 - type: Door - secondsUntilStateChange: -67401.266 + secondsUntilStateChange: -68431.75 state: Closing - uid: 1274 components: diff --git a/Resources/Maps/submarine.yml b/Resources/Maps/submarine.yml index 0890fe73aa5..123cc527dc1 100644 --- a/Resources/Maps/submarine.yml +++ b/Resources/Maps/submarine.yml @@ -100515,6 +100515,14 @@ entities: - type: Transform pos: 87.5,-19.5 parent: 2 +- proto: ComputerPsionicsRecords + entities: + - uid: 39308 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 32.5,28.5 + parent: 2 - proto: ComputerRadar entities: - uid: 6359 diff --git a/Resources/Maps/tortuga.yml b/Resources/Maps/tortuga.yml index f9f702c820c..df56bcd11fd 100644 --- a/Resources/Maps/tortuga.yml +++ b/Resources/Maps/tortuga.yml @@ -63598,6 +63598,14 @@ entities: rot: 1.5707963267948966 rad pos: 48.5,28.5 parent: 33 +- proto: ComputerPsionicsRecords + entities: + - uid: 28381 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -64.5,-6.5 + parent: 33 - proto: ComputerRadar entities: - uid: 3325 From 569850d7b256ecc2d2042cdfc366af08b7beb855 Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Mon, 20 Jan 2025 01:22:18 -0500 Subject: [PATCH 10/12] Fix a minor typo, lmao. --- Resources/Prototypes/Entities/Objects/Devices/cartridges.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml index d2780fef031..e8c6816feab 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml @@ -87,7 +87,7 @@ - type: Cartridge programName: log-probe-program-name icon: - sprite: Structures/Doors/Airlocks/Standard/psiurity.rsi + sprite: Structures/Doors/Airlocks/Standard/security.rsi state: closed - type: LogProbeCartridge - type: GuideHelp From 01c2be53c1fc81fc651182df3f5c3b7d31b10ec3 Mon Sep 17 00:00:00 2001 From: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Date: Mon, 20 Jan 2025 03:03:33 -0400 Subject: [PATCH 11/12] Update psionics-records.ftl Signed-off-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> --- .../psionics-records/psionics-records.ftl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Resources/Locale/en-US/psionics-records/psionics-records.ftl b/Resources/Locale/en-US/psionics-records/psionics-records.ftl index f53224530c0..ff2c2b8a4c5 100644 --- a/Resources/Locale/en-US/psionics-records/psionics-records.ftl +++ b/Resources/Locale/en-US/psionics-records/psionics-records.ftl @@ -8,9 +8,9 @@ psionics-records-console-no-record-found = No record was found for the selected psionics-records-console-status = Status psionics-records-status-none = None -psionics-records-status-registered = Registered -psionics-records-status-suspected = Suspected -psionics-records-status-abusing = Abusing +psionics-records-status-registered = Registered Psionic +psionics-records-status-suspected = Suspected Psionics +psionics-records-status-abusing = Abusing Psionics psionics-records-console-wanted-reason = [color=gray]Psionics Listed[/color] psionics-records-console-suspected-reason = [color=gray]Suspected Reason[/color] @@ -21,12 +21,12 @@ psionics-records-permission-denied = Permission denied ## Security channel notifications -psionics-records-console-registered = {$name} is registered by {$officer} with psionics: {$reason}. -psionics-records-console-suspected = {$officer} marked {$name} as suspicious because of: {$reason}. -psionics-records-console-not-suspected = {$name} is no longer a suspect. -psionics-records-console-not-registered = {$name} is no longer registered. -psionics-records-console-abusing = {$officer} marked {$name} as abusing because of: {$reason}. -psionics-records-console-not-abusing = {$name} is no longer marked abusing. +psionics-records-console-registered = {$name} is registered as psionic by {$officer}: {$reason}. +psionics-records-console-suspected = {$officer} marked {$name} as a possible psionic because of: {$reason}. +psionics-records-console-not-suspected = {$name} is no longer a suspected psionic. +psionics-records-console-not-registered = {$name} is no longer registered as psionic. +psionics-records-console-abusing = {$officer} marked {$name} as abusing psionics because of: {$reason}. +psionics-records-console-not-abusing = {$name} is no longer marked as abusing psionics. psionics-records-console-unknown-officer = ## Filters From c8feaeca12059180de7e3a040c1d2988a0c69b0f Mon Sep 17 00:00:00 2001 From: CerberusWolfie Date: Mon, 20 Jan 2025 02:33:06 -0500 Subject: [PATCH 12/12] I forgot to include the computers, lmao.... --- .../Entities/Structures/Machines/Computers/computers.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index de6c2b48839..b1432f6dc1c 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -423,12 +423,12 @@ guides: - CriminalRecords - parent: BaseComputer +- type: entity + parent: BaseComputerAiAccess id: ComputerPsionicsRecords name: psionics registry computer description: This can be used to check psionics registry records. Only epistemics can modify them. components: - - type: StationAiWhitelist - type: PsionicsRecordsConsole - type: UserInterface interfaces: