Skip to content

Commit

Permalink
Cherry-Pick the Secwatch Pda App (#502)
Browse files Browse the repository at this point in the history
# Description
Cherry-picks DeltaV-Station/Delta-v#1237

All credit goes to the original author, deltanedas

Adds a PDA app that lets seccies know who's wanted and who's about to be
thrown out of an airlock without relying on the sechud and people having
their IDs on them.

# Media


![image](https://github.com/Simple-Station/Einstein-Engines/assets/69920617/37f5fa1a-27a5-4392-b4bb-be0f1016b499)

(see the original PR for a better preview)

# Changelog

:cl: deltanedas
- add: Security can find the new SecWatch™ app in their PDAs to see
current suspects and wanted criminals.

Co-authored-by: deltanedas <[email protected]>
Co-authored-by: Azzy <[email protected]>
  • Loading branch information
3 people committed Jul 2, 2024
1 parent ffb9ec9 commit 7a12461
Show file tree
Hide file tree
Showing 18 changed files with 271 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,6 @@ public override Control GetUIFragmentRoot()
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_fragment = new CrimeAssistUiFragment();

_fragment.OnSync += _ => SendSyncMessage(userInterface);
}

private void SendSyncMessage(BoundUserInterface userInterface)
{
var syncMessage = new CrimeAssistSyncMessageEvent();
var message = new CartridgeUiMessage(syncMessage);
userInterface.SendMessage(message);
}

public override void UpdateState(BoundUserInterfaceState state)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Content.Client.Message;
using Content.Shared.DeltaV.CartridgeLoader.Cartridges;
using Robust.Client.AutoGenerated;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
Expand All @@ -13,9 +12,7 @@ namespace Content.Client.DeltaV.CartridgeLoader.Cartridges;
public sealed partial class CrimeAssistUiFragment : BoxContainer
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;

public event Action<bool>? OnSync;
private CrimeAssistPage _currentPage;
private List<CrimeAssistPage>? _pages;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:cartridges="clr-namespace:Content.Client.DeltaV.CartridgeLoader.Cartridges"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
HorizontalExpand="True"
VerticalExpand="True"
Margin="5">
<!-- All labels populated in constructor -->
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Left">
<BoxContainer Orientation="Vertical">
<Label Name="Status"/>
<Label Text="{Loc 'criminal-records-console-reason'}"/>
</BoxContainer>
<customControls:VSeparator StyleClasses="LowDivider" Margin="8 0"/>
<BoxContainer Orientation="Vertical">
<Label Name="Title"/>
<Label Name="Reason"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
Original file line number Diff line number Diff line change
@@ -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.DeltaV.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");
}
}
27 changes: 27 additions & 0 deletions Content.Client/DeltaV/CartridgeLoader/Cartridges/SecWatchUi.cs
Original file line number Diff line number Diff line change
@@ -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.DeltaV.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);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<cartridges:SecWatchUiFragment xmlns="https://spacestation14.io"
xmlns:cartridges="clr-namespace:Content.Client.DeltaV.CartridgeLoader.Cartridges"
Margin="5"
VerticalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<Label Text="{Loc 'sec-watch-title'}" HorizontalExpand="True" HorizontalAlignment="Center"/>
<Label Name="NoEntries" Text="{Loc 'sec-watch-no-entries'}" HorizontalExpand="True" HorizontalAlignment="Center" Visible="False"/>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
<!-- Populated when state received -->
<BoxContainer Name="Entries" Orientation="Vertical" VerticalAlignment="Top"/>
</ScrollContainer>
</BoxContainer>
</cartridges:SecWatchUiFragment>
Original file line number Diff line number Diff line change
@@ -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.DeltaV.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));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Content.Shared.Security;

namespace Content.Server.CartridgeLoader.Cartridges;

[RegisterComponent, Access(typeof(SecWatchCartridgeSystem))]
public sealed partial class SecWatchCartridgeComponent : Component
{
/// <summary>
/// Only show people with these statuses.
/// </summary>
[DataField]
public List<SecurityStatus> Statuses = new()
{
SecurityStatus.Suspected,
SecurityStatus.Wanted
};

/// <summary>
/// Station entity thats getting its records checked.
/// </summary>
[DataField]
public EntityUid? Station;
}
Original file line number Diff line number Diff line change
@@ -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<RecordModifiedEvent>(OnRecordModified);

SubscribeLocalEvent<SecWatchCartridgeComponent, CartridgeUiReadyEvent>(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<SecWatchCartridgeComponent, CartridgeComponent>();
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<SecWatchCartridgeComponent> ent, ref CartridgeUiReadyEvent args)
{
UpdateUI(ent, args.Loader);
}

private void UpdateUI(Entity<SecWatchCartridgeComponent> 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<StationRecordsComponent>(ent.Comp.Station, out var records))
return;

station = ent.Comp.Station.Value;

var entries = new List<SecWatchEntry>();
foreach (var (id, criminal) in _records.GetRecordsOfType<CriminalRecord>(station, records))
{
if (!ent.Comp.Statuses.Contains(criminal.Status))
continue;

var key = new StationRecordKey(id, station);
if (!_records.TryGetRecord<GeneralStationRecord>(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);
}
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Content.Shared.Security;
using Robust.Shared.Serialization;

namespace Content.Shared.CartridgeLoader.Cartridges;

/// <summary>
/// Show a list of wanted and suspected people from criminal records.
/// </summary>
[Serializable, NetSerializable]
public sealed class SecWatchUiState : BoundUserInterfaceState
{
public readonly List<SecWatchEntry> Entries;

public SecWatchUiState(List<SecWatchEntry> entries)
{
Entries = entries;
}
}

/// <summary>
/// Entry for a person who is wanted or suspected.
/// </summary>
[Serializable, NetSerializable]
public record struct SecWatchEntry(string Name, string Job, SecurityStatus Status, string? Reason);
5 changes: 5 additions & 0 deletions Resources/Locale/en-US/deltav/cartridge-loader/secwatch.ftl
Original file line number Diff line number Diff line change
@@ -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}, {$job}
sec-watch-no-reason = None given???
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,24 @@
icon:
sprite: DeltaV/Icons/cri.rsi
state: cri
- type: CrimeAssistCartridge

- 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: DeltaV/Objects/Devices/cartridge.rsi
state: cart-cri
- type: Icon
sprite: DeltaV/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
3 changes: 2 additions & 1 deletion Resources/Prototypes/DeltaV/Entities/Objects/Devices/pda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
map: [ "enum.PdaVisualLayers.IdLight" ]
shader: "unshaded"
visible: false
- type: CartridgeLoader # DeltaV - Crime Assist
- type: CartridgeLoader # DeltaV - Crime Assist + SecWatch
preinstalled:
- CrewManifestCartridge
- NotekeeperCartridge
- NewsReaderCartridge
- CrimeAssistCartridge
- SecWatchCartridge
- type: Pda
id: BrigmedicIDCard
state: pda-corpsman
Expand Down
Loading

0 comments on commit 7a12461

Please sign in to comment.