Security update (#323)

* add: security hud update

* access & fix names

* translates

* fix

* - fix: Fixes.

* - fix: Условно-досрочно.

---------

Co-authored-by: CaYpeN1 <artem7771art@gmail.com>
This commit is contained in:
Aviu00
2024-06-01 13:28:21 +00:00
committed by GitHub
parent 657d3f0a2a
commit 231927a577
17 changed files with 390 additions and 51 deletions

View File

@@ -0,0 +1,122 @@
using System.Linq;
using Content.Client._White.UserInterface.Radial;
using Content.Shared._White.SecurityHud;
using Content.Shared.Security;
using Content.Shared.StatusIcon;
using Robust.Shared.Prototypes;
namespace Content.Client._White.SecurityHud;
public sealed class SecurityHudBUI : BoundUserInterface
{
private RadialContainer? _radialContainer;
private bool _updated;
private readonly Dictionary<string, string> _names = new()
{
{ "SecurityIconDischarged", Loc.GetString("criminal-records-status-discharged")},
{ "SecurityIconParoled", Loc.GetString("criminal-records-status-paroled")},
{ "SecurityIconSuspected", Loc.GetString("criminal-records-status-suspected")},
{ "SecurityIconWanted", Loc.GetString("criminal-records-status-wanted")},
{ "SecurityIconIncarcerated", Loc.GetString("criminal-records-status-detained")},
{ "CriminalRecordIconRemove", Loc.GetString("security-hud-remove-status") }
};
private readonly Dictionary<string, string> _icons = new()
{
{ "SecurityIconDischarged", "/Textures/White/Interface/securityhud.rsi/discharged.png" },
{ "SecurityIconParoled", "/Textures/White/Interface/securityhud.rsi/paroled.png" },
{ "SecurityIconSuspected", "/Textures/White/Interface/securityhud.rsi/suspected.png" },
{ "SecurityIconWanted", "/Textures/White/Interface/securityhud.rsi/wanted.png" },
{ "SecurityIconIncarcerated", "/Textures/White/Interface/securityhud.rsi/incarcerated.png" },
{ "CriminalRecordIconRemove", "/Textures/White/Interface/securityhud.rsi/remove.png" }
};
private readonly Dictionary<string, SecurityStatus> _status = new()
{
{ "SecurityIconDischarged", SecurityStatus.Discharged },
{ "SecurityIconParoled", SecurityStatus.Paroled },
{ "SecurityIconSuspected", SecurityStatus.Suspected },
{ "SecurityIconWanted", SecurityStatus.Wanted },
{ "SecurityIconIncarcerated", SecurityStatus.Detained },
{ "CriminalRecordIconRemove", SecurityStatus.None }
};
public SecurityHudBUI(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
if (_radialContainer != null)
UIReset();
_radialContainer = new RadialContainer();
_radialContainer.Closed += Close;
if (State != null)
UpdateState(State);
}
private void UIReset()
{
_radialContainer?.Close();
_radialContainer = null;
_updated = false;
}
private void PopulateRadial(IReadOnlyCollection<string> ids, NetEntity user, NetEntity target)
{
foreach (var id in ids)
{
if (_radialContainer == null)
continue;
if(!_names.TryGetValue(id, out var name) || !_icons.TryGetValue(id, out var icon) || !_status.TryGetValue(id, out var status))
return;
var button = _radialContainer.AddButton(name, icon);
button.Controller.OnPressed += _ =>
{
Select(status, user, target);
};
}
}
private void Select(SecurityStatus status, NetEntity user, NetEntity target)
{
SendMessage(new SecurityHudStatusSelectedMessage(status, user, target));
UIReset();
Close();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
UIReset();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_updated)
return;
if (state is SecurityHudBUIState newState)
{
PopulateRadial(newState.Ids, newState.User, newState.Target);
}
if (_radialContainer == null)
return;
_radialContainer?.OpenAttachedLocalPlayer();
_updated = true;
}
}

View File

@@ -0,0 +1,20 @@
using Content.Shared.Radio;
using Content.Shared.StatusIcon;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Server._White.SecurityHud;
[RegisterComponent]
public sealed partial class SecurityHudComponent : Component
{
[ViewVariables(VVAccess.ReadOnly)]
[DataField("criminalrecords", customTypeSerializer: typeof(PrototypeIdListSerializer<StatusIconPrototype>))]
public IReadOnlyCollection<string> Status = ArraySegment<string>.Empty;
[ViewVariables(VVAccess.ReadOnly)]
public ProtoId<RadioChannelPrototype> SecurityChannel = "Security";
[ViewVariables(VVAccess.ReadOnly)]
public string Reason = "Изменено с помощью визора";
}

View File

@@ -0,0 +1,153 @@
using Content.Server.Access.Systems;
using Content.Server.CriminalRecords.Systems;
using Content.Server.Popups;
using Content.Server.Radio.EntitySystems;
using Content.Server.StationRecords.Systems;
using Content.Shared._Miracle.Components;
using Content.Shared._White.SecurityHud;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.CriminalRecords;
using Content.Shared.Humanoid;
using Content.Shared.Inventory;
using Content.Shared.Popups;
using Content.Shared.Security;
using Content.Shared.Security.Components;
using Content.Shared.StationRecords;
using Content.Shared.Verbs;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
namespace Content.Server._White.SecurityHud;
public sealed class SecurityHudSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly CriminalRecordsSystem _criminalRecordsSystem = default!;
[Dependency] private readonly CriminalRecordsConsoleSystem _criminalRecordsConsoleSystem = default!;
[Dependency] private readonly StationRecordsSystem _stationRecordsSystem = default!;
[Dependency] private readonly IdCardSystem _idCardSystem = default!;
[Dependency] private readonly RadioSystem _radio = default!;
[Dependency] private readonly InventorySystem _invSlotsSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GetVerbsEvent<AlternativeVerb>>(OnAltVerb);
SubscribeLocalEvent<SecurityHudComponent, SecurityHudStatusSelectedMessage>(OnStatusSelected);
}
private void OnAltVerb(GetVerbsEvent<AlternativeVerb> args)
{
if(!HasComp<HumanoidAppearanceComponent>(args.Target))
return;
if(!_invSlotsSystem.TryGetSlotEntity(args.User, "eyes", out var ent))
return;
if(!TryComp<SecurityHudComponent>(ent, out var component))
return;
if(!TryComp<AccessReaderComponent>(ent, out var accessReaderComponent))
return;
if (!_accessReaderSystem.IsAllowed(args.User, (EntityUid) ent, accessReaderComponent))
{
_popupSystem.PopupEntity(Loc.GetString("security-hud-not-allowed"), args.User, args.User, PopupType.Medium);
return;
}
AlternativeVerb verb = new()
{
Act = () =>
{
SetWanted(args.User, args.Target, ent.Value, component);
},
Disabled = false,
Priority = 0,
Text = Loc.GetString("security-hud-verb"),
};
args.Verbs.Add(verb);
}
private void SetWanted(EntityUid uid, EntityUid target, EntityUid hud, SecurityHudComponent component)
{
if (!TryComp<ActorComponent>(uid, out var actor))
return;
if (_ui.TryGetUi(hud, SecurityHudUiKey.Key, out var bui))
{
_ui.SetUiState(bui, new SecurityHudBUIState(component.Status, GetNetEntity(uid), GetNetEntity(target)));
_ui.OpenUi(bui, actor.PlayerSession);
}
}
private void OnStatusSelected(EntityUid uid, SecurityHudComponent component, SecurityHudStatusSelectedMessage args)
{
var user = GetEntity(args.User);
var target = GetEntity(args.Target);
if (!_idCardSystem.TryFindIdCard(target, out var idCard))
{
_popupSystem.PopupEntity(Loc.GetString("security-hud-id-unknown"), user, user, PopupType.Medium);
return;
}
if(!TryComp<StationRecordKeyStorageComponent>(idCard, out var stationRecordKeyComp))
return;
if (stationRecordKeyComp.Key == null)
{
_popupSystem.PopupEntity(Loc.GetString("security-hud-key-null"), user, user, PopupType.Medium);
return;
}
var key = stationRecordKeyComp.Key.Value;
if (!SetCriminalStatus(key, args.Status, uid, user, idCard.Comp, component.Reason, component.SecurityChannel))
{
_popupSystem.PopupEntity(Loc.GetString("security-hud-cant-set-status"), user, user, PopupType.Medium);
}
}
private bool SetCriminalStatus(StationRecordKey key, SecurityStatus status, EntityUid hud, EntityUid officer,
IdCardComponent idCard, string reason, string securityChannel)
{
if (!_stationRecordsSystem.TryGetRecord<GeneralStationRecord>(key, out var generalRecord))
return false;
if (!_stationRecordsSystem.TryGetRecord<CriminalRecord>(key, out var record) || record.Status == status)
return false;
var name = generalRecord.Name;
var officerName = Loc.GetString("criminal-records-console-unknown-officer");
if (_idCardSystem.TryFindIdCard(officer, out var id) && id.Comp.FullName is { } fullName)
officerName = fullName;
_criminalRecordsSystem.TryChangeStatus(key, status, reason);
var locArgs = new (string, object)[] { ("name", name), ("officer", officerName), ("reason", reason) };
var statusString = (record.Status, status) switch
{
(_, SecurityStatus.Detained) => "detained",
(_, SecurityStatus.Suspected) => "suspected",
(_, SecurityStatus.Paroled) => "paroled",
(_, SecurityStatus.Discharged) => "released",
(_, SecurityStatus.Wanted) => "wanted",
(SecurityStatus.Suspected, SecurityStatus.None) => "not-suspected",
(SecurityStatus.Wanted, SecurityStatus.None) => "not-wanted",
(SecurityStatus.Detained, SecurityStatus.None) => "released",
(SecurityStatus.Paroled, SecurityStatus.None) => "not-parole",
_ => "not-wanted"
};
_radio.SendRadioMessage(hud, Loc.GetString($"criminal-records-console-{statusString}", locArgs), securityChannel, hud);
_criminalRecordsConsoleSystem.UpdateCriminalIdentity(name, status);
return true;
}
}

View File

@@ -0,0 +1,44 @@
using Content.Shared.Security;
using Robust.Shared.Serialization;
namespace Content.Shared._White.SecurityHud;
[Serializable, NetSerializable]
public enum SecurityHudUiKey
{
Key
}
[Serializable, NetSerializable]
public sealed class SecurityHudBUIState : BoundUserInterfaceState
{
public IReadOnlyCollection<string> Ids { get; set; }
public NetEntity User { get; set; }
public NetEntity Target { get; private set; }
public SecurityHudBUIState(IReadOnlyCollection<string> ids, NetEntity user, NetEntity target)
{
Ids = ids;
User = user;
Target = target;
}
}
[Serializable, NetSerializable]
public class SecurityHudStatusSelectedMessage : BoundUserInterfaceMessage
{
public SecurityStatus Status { get; private set; }
public NetEntity User { get; private set; }
public NetEntity Target { get; private set; }
public SecurityHudStatusSelectedMessage(SecurityStatus status, NetEntity user, NetEntity target)
{
Status = status;
User = user;
Target = target;
}
}

View File

@@ -10,11 +10,12 @@ criminal-records-console-status = Статус
criminal-records-status-none = Нет
criminal-records-status-wanted = В розыске
criminal-records-status-detained = В заключении
criminal-records-status-suspected = Подозреваемый
criminal-records-status-released = Отпущен
criminal-records-status-discharged = Освобождён
criminal-records-status-paroled = Досрочно освобождён
criminal-records-console-wanted-reason = [color=gray]Причина розыска[/color]
criminal-records-console-suspected-reason = [color=gray]Причина подозрения[/color]
criminal-records-console-reason = Причина
criminal-records-console-reason-placeholder = Например: {$placeholder}
@@ -31,12 +32,15 @@ criminal-records-permission-denied = Доступ воспрещен
## Security channel notifications
criminal-records-console-wanted = {$name} отправлен в розыск по указу {$officer} по причине: {$reason}.
criminal-records-console-suspected = {$name} подозревается по указу {$officer} по причине: {$reason}.
criminal-records-console-not-suspected = {$name} больше не под подозрением.
criminal-records-console-detained = {$name} был задержан {$officer}.
criminal-records-console-released = {$name} был задержан {$officer}.
criminal-records-console-released = {$name} был освобожден {$officer}.
criminal-records-console-not-wanted = {$name} больше не в розыске.
criminal-records-console-paroled = {$name} был отпущен условно-досрочно {$officer}.
criminal-records-console-not-parole = {$name} больше не условно-досрочно освобождённый.
criminal-records-console-unknown-officer = <неизвестный офицер>
criminal-records-console-suspected = {$name} подозревается по указу {$officer} по причине: {$reason}.
## Filters

View File

@@ -0,0 +1,6 @@
security-hud-key-null = Визор не может установить личность человека!
security-hud-id-unknown = Визор не может установить идентификационную карту человека!
security-hud-verb = Изменить статус
security-hud-cant-set-status = Произошла ошибка при попытке установить статус!
security-hud-remove-status = Убрать статус.
security-hud-not-allowed = Недостаточный доступ для взаимодействия.

View File

@@ -44,6 +44,20 @@
- type: Clothing
sprite: Clothing/Eyes/Hud/sec.rsi
- type: ShowSecurityIcons
- type: AccessReader
access: [["Security"]]
- type: SecurityHud
criminalrecords:
- SecurityIconDischarged
- SecurityIconParoled
- SecurityIconSuspected
- SecurityIconWanted
- SecurityIconIncarcerated
- CriminalRecordIconRemove
- type: UserInterface
interfaces:
- key: enum.SecurityHudUiKey.Key
type: SecurityHudBUI
- type: Tag
tags:
- HudSecurity

View File

@@ -1,47 +0,0 @@
- type: statusIcon
id: CriminalRecordIcon
abstract: true
priority: 2
locationPreference: Right
- type: statusIcon
parent: CriminalRecordIcon
id: CriminalRecordIconReleased
icon:
sprite: /Textures/White/Interface/records.rsi
state: released
- type: statusIcon
parent: CriminalRecordIcon
id: CriminalRecordIconDischarged
icon:
sprite: /Textures/White/Interface/records.rsi
state: discharged
- type: statusIcon
parent: CriminalRecordIcon
id: CriminalRecordIconParolled
icon:
sprite: /Textures/White/Interface/records.rsi
state: parolled
- type: statusIcon
parent: CriminalRecordIcon
id: CriminalRecordIconSuspected
icon:
sprite: /Textures/White/Interface/records.rsi
state: suspected
- type: statusIcon
parent: CriminalRecordIcon
id: CriminalRecordIconWanted
icon:
sprite: /Textures/White/Interface/records.rsi
state: wanted
- type: statusIcon
parent: CriminalRecordIcon
id: CriminalRecordIconIncarcerated
icon:
sprite: /Textures/White/Interface/records.rsi
state: incarcerated

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 141 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

View File

@@ -0,0 +1,23 @@
{
"license": "CC-BY-SA-3.0",
"copyright": "https://github.com/tgstation/tgstation/blob/8e49222b72f6fdcbe741d2a6ce0a8425d95010b7/icons/mob/huds/hud.dmi",
"version": 1,
"size": { "y": 32, "x": 32 },
"states": [
{
"name": "wanted"
},
{
"name": "suspected"
},
{
"name": "released"
},
{
"name": "incarcerated"
},
{
"name": "remove"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B