diff --git a/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml new file mode 100644 index 00000000000..12440db5d9b --- /dev/null +++ b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs new file mode 100644 index 00000000000..0b3bd362d2c --- /dev/null +++ b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchEntryControl.xaml.cs @@ -0,0 +1,21 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._CorvaxNext.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchEntryControl : BoxContainer +{ + public SecWatchEntryControl(SecWatchEntry entry) + { + RobustXamlLoader.Load(this); + + Status.Text = Loc.GetString($"criminal-records-status-{entry.Status.ToString().ToLower()}"); + Title.Text = Loc.GetString("sec-watch-entry", ("name", entry.Name), ("job", entry.Job)); + + Reason.Text = entry.Reason ?? Loc.GetString("sec-watch-no-reason"); + } +} \ No newline at end of file diff --git a/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUi.cs b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUi.cs new file mode 100644 index 00000000000..838f4395c73 --- /dev/null +++ b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUi.cs @@ -0,0 +1,27 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.UserInterface; + +namespace Content.Client._CorvaxNext.CartridgeLoader.Cartridges; + +public sealed partial class SecWatchUi : UIFragment +{ + private SecWatchUiFragment? _fragment; + + public override Control GetUIFragmentRoot() + { + return _fragment!; + } + + public override void Setup(BoundUserInterface ui, EntityUid? owner) + { + _fragment = new SecWatchUiFragment(); + } + + public override void UpdateState(BoundUserInterfaceState state) + { + if (state is SecWatchUiState cast) + _fragment?.UpdateState(cast); + } +} \ No newline at end of file diff --git a/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml new file mode 100644 index 00000000000..4ebea90f59c --- /dev/null +++ b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs new file mode 100644 index 00000000000..068ff2c8a38 --- /dev/null +++ b/Content.Client/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiFragment.xaml.cs @@ -0,0 +1,25 @@ +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._CorvaxNext.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class SecWatchUiFragment : BoxContainer +{ + public SecWatchUiFragment() + { + RobustXamlLoader.Load(this); + } + + public void UpdateState(SecWatchUiState state) + { + NoEntries.Visible = state.Entries.Count == 0; + Entries.RemoveAllChildren(); + foreach (var entry in state.Entries) + { + Entries.AddChild(new SecWatchEntryControl(entry)); + } + } +} \ No newline at end of file diff --git a/Content.Server/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs b/Content.Server/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs new file mode 100644 index 00000000000..c0ca5ad9dee --- /dev/null +++ b/Content.Server/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchCartridgeComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Security; + +namespace Content.Server.CartridgeLoader.Cartridges; + +[RegisterComponent, Access(typeof(SecWatchCartridgeSystem))] +public sealed partial class SecWatchCartridgeComponent : Component +{ + /// + /// Only show people with these statuses. + /// + [DataField] + public List Statuses = new() + { + SecurityStatus.Wanted, + SecurityStatus.Detained + }; + + /// + /// Station entity thats getting its records checked. + /// + [DataField] + public EntityUid? Station; +} diff --git a/Content.Server/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs b/Content.Server/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs new file mode 100644 index 00000000000..2b46637da12 --- /dev/null +++ b/Content.Server/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchCartridgeSystem.cs @@ -0,0 +1,73 @@ +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.CriminalRecords; +using Content.Shared.StationRecords; + +namespace Content.Server.CartridgeLoader.Cartridges; + +public sealed class SecWatchCartridgeSystem : 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 SecWatchEntry(general.Name, general.JobTitle, criminal.Status, criminal.Reason)); + } + + var state = new SecWatchUiState(entries); + _cartridgeLoader.UpdateCartridgeUiState(loader, state); + } +} \ No newline at end of file diff --git a/Content.Shared/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiState.cs b/Content.Shared/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiState.cs new file mode 100644 index 00000000000..29720630c43 --- /dev/null +++ b/Content.Shared/_CorvaxNext/CartridgeLoader/Cartridges/SecWatchUiState.cs @@ -0,0 +1,24 @@ +using Content.Shared.Security; +using Robust.Shared.Serialization; + +namespace Content.Shared.CartridgeLoader.Cartridges; + +/// +/// Show a list of wanted and suspected people from criminal records. +/// +[Serializable, NetSerializable] +public sealed class SecWatchUiState : BoundUserInterfaceState +{ + public readonly List Entries; + + public SecWatchUiState(List entries) + { + Entries = entries; + } +} + +/// +/// Entry for a person who is wanted or suspected. +/// +[Serializable, NetSerializable] +public record struct SecWatchEntry(string Name, string Job, SecurityStatus Status, string? Reason); \ No newline at end of file diff --git a/Resources/Locale/en-US/_corvaxnext/cartridge-loader/secwatch.ftl b/Resources/Locale/en-US/_corvaxnext/cartridge-loader/secwatch.ftl new file mode 100644 index 00000000000..ca18db233aa --- /dev/null +++ b/Resources/Locale/en-US/_corvaxnext/cartridge-loader/secwatch.ftl @@ -0,0 +1,5 @@ +sec-watch-program-name = SecWatch +sec-watch-title = SecWatch 1.0 +sec-watch-no-entries = Everything's calm. Why not enjoy a Monkin Donut? +sec-watch-entry = {$name} +sec-watch-no-reason = None given??? \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_corvaxnext/cartridge-loader/secwatch.ftl b/Resources/Locale/ru-RU/_corvaxnext/cartridge-loader/secwatch.ftl new file mode 100644 index 00000000000..bd9a5070cb0 --- /dev/null +++ b/Resources/Locale/ru-RU/_corvaxnext/cartridge-loader/secwatch.ftl @@ -0,0 +1,5 @@ +sec-watch-program-name = ОКО СБ +sec-watch-title = ОКО СБ 1.0 +sec-watch-no-entries = Полный порядок. Безопасность превыше всего. +sec-watch-entry = {$name} +sec-watch-no-reason = Причина не уточнена. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/ss14-ru/prototypes/_corvaxnext/entities/objects/devices/cartriges.ftl b/Resources/Locale/ru-RU/ss14-ru/prototypes/_corvaxnext/entities/objects/devices/cartriges.ftl new file mode 100644 index 00000000000..427dadde5e1 --- /dev/null +++ b/Resources/Locale/ru-RU/ss14-ru/prototypes/_corvaxnext/entities/objects/devices/cartriges.ftl @@ -0,0 +1,2 @@ +ent-SecWatchCartridge = картридж "око сб" + .desc = Картридж, отслеживающий статус разыскиваемых службой безопасности лиц. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 4febc87b90f..8b13d2598bb 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -76,6 +76,7 @@ - CrewManifestCartridge - NotekeeperCartridge - NewsReaderCartridge + - SecWatchCartridge # Corvax-Next-SecWatch cartridgeSlot: priority: -1 name: device-pda-slot-component-slot-name-cartridge @@ -138,6 +139,7 @@ - NotekeeperCartridge - NewsReaderCartridge - MedTekCartridge + - SecWatchCartridge # Corvax-Next-SecWatch - type: entity parent: BasePDA @@ -408,6 +410,7 @@ - NotekeeperCartridge - NewsReaderCartridge - AstroNavCartridge + - SecWatchCartridge # Corvax-Next-SecWatch - type: entity parent: BasePDA @@ -773,6 +776,7 @@ - WantedListCartridge - MedTekCartridge - AstroNavCartridge + - SecWatchCartridge # Corvax-Next-SecWatch - type: entity parent: CentcomPDA diff --git a/Resources/Prototypes/_CorvaxNext/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/_CorvaxNext/Entities/Objects/Devices/cartridges.yml new file mode 100644 index 00000000000..b271eb6378f --- /dev/null +++ b/Resources/Prototypes/_CorvaxNext/Entities/Objects/Devices/cartridges.yml @@ -0,0 +1,20 @@ +- type: entity + parent: BaseItem + id: SecWatchCartridge + name: sec watch cartridge + description: A cartridge that tracks the status of currently wanted individuals. + components: + - type: Sprite + sprite: _CorvaxNext/Objects/Devices/cartridge.rsi + state: cart-cri + - type: Icon + sprite: _CorvaxNext/Objects/Devices/cartridge.rsi + state: cart-cri + - type: UIFragment + ui: !type:SecWatchUi + - type: Cartridge + programName: sec-watch-program-name + icon: + sprite: Objects/Weapons/Melee/stunbaton.rsi + state: stunbaton_on + - type: SecWatchCartridge \ No newline at end of file diff --git a/Resources/Textures/_CorvaxNext/Objects/Devices/cartridge.rsi/cart-cri.png b/Resources/Textures/_CorvaxNext/Objects/Devices/cartridge.rsi/cart-cri.png new file mode 100644 index 00000000000..4da4343e584 Binary files /dev/null and b/Resources/Textures/_CorvaxNext/Objects/Devices/cartridge.rsi/cart-cri.png differ diff --git a/Resources/Textures/_CorvaxNext/Objects/Devices/cartridge.rsi/meta.json b/Resources/Textures/_CorvaxNext/Objects/Devices/cartridge.rsi/meta.json new file mode 100644 index 00000000000..0eb27fde855 --- /dev/null +++ b/Resources/Textures/_CorvaxNext/Objects/Devices/cartridge.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Timfa, plus edits by portfiend", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "cart-cri" + } + ] +} \ No newline at end of file