Skip to content

Commit

Permalink
Cherry-picked commit 60b9d89 from space-wizards/space-station-14/master
Browse files Browse the repository at this point in the history
  • Loading branch information
Arendian authored and SimpleStation14 committed Apr 21, 2024
1 parent 3bf08c7 commit 8b8fcd4
Show file tree
Hide file tree
Showing 19 changed files with 230 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ protected override void Open()
SendMessage(new SetStationRecordFilter(type, filterValue));
_window.OnStatusSelected += status =>
SendMessage(new CriminalRecordChangeStatus(status, null));
_window.OnDialogConfirmed += (_, reason) =>
SendMessage(new CriminalRecordChangeStatus(SecurityStatus.Wanted, reason));
_window.OnDialogConfirmed += (status, reason) =>
SendMessage(new CriminalRecordChangeStatus(status, reason));
_window.OnHistoryUpdated += UpdateHistory;
_window.OnHistoryClosed += () => _historyWindow?.Close();
_window.OnClose += Close;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,16 +219,16 @@ private void FilterListingOfRecords(string text = "")

private void SetStatus(SecurityStatus status)
{
if (status == SecurityStatus.Wanted)
if (status == SecurityStatus.Wanted || status == SecurityStatus.Suspected)
{
GetWantedReason();
GetReason(status);
return;
}

OnStatusSelected?.Invoke(status);
}

private void GetWantedReason()
private void GetReason(SecurityStatus status)
{
if (_reasonDialog != null)
{
Expand All @@ -237,7 +237,7 @@ private void GetWantedReason()
}

var field = "reason";
var title = Loc.GetString("criminal-records-status-wanted");
var title = Loc.GetString("criminal-records-status-" + status.ToString().ToLower());
var placeholders = _proto.Index<DatasetPrototype>(ReasonPlaceholders);
var placeholder = Loc.GetString("criminal-records-console-reason-placeholder", ("placeholder", _random.Pick(placeholders.Values))); // just funny it doesn't actually get used
var prompt = Loc.GetString("criminal-records-console-reason");
Expand All @@ -251,7 +251,7 @@ private void GetWantedReason()
if (reason.Length < 1 || reason.Length > _maxLength)
return;
OnDialogConfirmed?.Invoke(SecurityStatus.Wanted, reason);
OnDialogConfirmed?.Invoke(status, reason);
};

_reasonDialog.OnClose += () => { _reasonDialog = null; };
Expand Down
7 changes: 6 additions & 1 deletion Content.Client/Overlays/ShowSecurityIconsSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Content.Shared.Mindshield.Components;
using Content.Shared.Overlays;
using Content.Shared.PDA;
using Content.Shared.Security.Components;
using Content.Shared.StatusIcon;
using Content.Shared.StatusIcon.Components;
using Robust.Shared.Prototypes;
Expand Down Expand Up @@ -74,7 +75,11 @@ private IReadOnlyList<StatusIconPrototype> DecideSecurityIcon(EntityUid uid)
result.Add(icon);
}

// Add arrest icons here, WYCI.
if (TryComp<CriminalRecordComponent>(uid, out var record))
{
if(_prototypeMan.TryIndex<StatusIconPrototype>(record.StatusIcon.Id, out var criminalIcon))
result.Add(criminalIcon);
}

return result;
}
Expand Down
2 changes: 1 addition & 1 deletion Content.Server/Administration/Systems/AdminSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public void UpdatePlayerList(ICommonSession player)
return value ?? null;
}

private void OnIdentityChanged(IdentityChangedEvent ev)
private void OnIdentityChanged(ref IdentityChangedEvent ev)
{
if (!TryComp<ActorComponent>(ev.CharacterEntity, out var actor))
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.IdentityManagement;
using Content.Shared.Security.Components;

namespace Content.Server.CriminalRecords.Systems;

Expand Down Expand Up @@ -71,7 +73,8 @@ private void OnFiltersChanged(Entity<CriminalRecordsConsoleComponent> ent, ref S
private void OnChangeStatus(Entity<CriminalRecordsConsoleComponent> ent, ref CriminalRecordChangeStatus msg)
{
// prevent malf client violating wanted/reason nullability
if ((msg.Status == SecurityStatus.Wanted) != (msg.Reason != null))
if (msg.Status == SecurityStatus.Wanted != (msg.Reason != null) &&
msg.Status == SecurityStatus.Suspected != (msg.Reason != null))
return;

if (!CheckSelected(ent, msg.Session, out var mob, out var key))
Expand Down Expand Up @@ -105,7 +108,7 @@ private void OnChangeStatus(Entity<CriminalRecordsConsoleComponent> ent, ref Cri

var name = RecordName(key.Value);
var officer = Loc.GetString("criminal-records-console-unknown-officer");
if (_idCard.TryFindIdCard(mob.Value, out var id) && id.Comp.FullName is {} fullName)
if (_idCard.TryFindIdCard(mob.Value, out var id) && id.Comp.FullName is { } fullName)
officer = fullName;

(string, object)[] args;
Expand All @@ -117,20 +120,32 @@ private void OnChangeStatus(Entity<CriminalRecordsConsoleComponent> ent, ref Cri
// figure out which radio message to send depending on transition
var statusString = (oldStatus, msg.Status) switch
{
// going from wanted or detained on the spot
// person has been detained
(_, SecurityStatus.Detained) => "detained",
// person did something sus
(_, SecurityStatus.Suspected) => "suspected",
// released on parole
(_, SecurityStatus.Paroled) => "paroled",
// prisoner did their time
(SecurityStatus.Detained, SecurityStatus.None) => "released",
// going from wanted to none, must have been a mistake
(_, SecurityStatus.None) => "not-wanted",
// going from none or detained, AOS or prisonbreak / lazy secoff never set them to released and they reoffended
(_, SecurityStatus.Discharged) => "released",
// going from any other state to wanted, AOS or prisonbreak / lazy secoff never set them to released and they reoffended
(_, SecurityStatus.Wanted) => "wanted",
// person is no longer sus
(SecurityStatus.Suspected, SecurityStatus.None) => "not-suspected",
// going from wanted to none, must have been a mistake
(SecurityStatus.Wanted, SecurityStatus.None) => "not-wanted",
// criminal status removed
(SecurityStatus.Detained, SecurityStatus.None) => "released",
// criminal is no longer on parole
(SecurityStatus.Paroled, SecurityStatus.None) => "not-parole",
// this is impossible
_ => "not-wanted"
};
_radio.SendRadioMessage(ent, Loc.GetString($"criminal-records-console-{statusString}", args), ent.Comp.SecurityChannel, ent);
_radio.SendRadioMessage(ent, Loc.GetString($"criminal-records-console-{statusString}", args),
ent.Comp.SecurityChannel, ent);

UpdateUserInterface(ent);
UpdateCriminalIdentity(name, msg.Status);
}

private void OnAddHistory(Entity<CriminalRecordsConsoleComponent> ent, ref CriminalRecordAddHistory msg)
Expand Down Expand Up @@ -177,7 +192,7 @@ private void UpdateUserInterface(Entity<CriminalRecordsConsoleComponent> ent)
var listing = _stationRecords.BuildListing((owningStation.Value, stationRecords), console.Filter);

var state = new CriminalRecordsConsoleState(listing, console.Filter);
if (console.ActiveKey is {} id)
if (console.ActiveKey is { } id)
{
// get records to display when a crewmember is selected
var key = new StationRecordKey(id, owningStation.Value);
Expand All @@ -198,7 +213,7 @@ private bool CheckSelected(Entity<CriminalRecordsConsoleComponent> ent, ICommonS
{
key = null;
mob = null;
if (session.AttachedEntity is not {} user)
if (session.AttachedEntity is not { } user)
return false;

if (!_access.IsAllowed(user, ent))
Expand All @@ -207,11 +222,11 @@ private bool CheckSelected(Entity<CriminalRecordsConsoleComponent> ent, ICommonS
return false;
}

if (ent.Comp.ActiveKey is not {} id)
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)
if (_station.GetOwningStation(ent) is not { } station)
return false;

key = new StationRecordKey(id, station);
Expand All @@ -229,4 +244,29 @@ private string RecordName(StationRecordKey key)

return record.Name;
}

/// <summary>
/// Checks if the new identity's name has a criminal record attached to it, and gives the entity the icon that
/// belongs to the status if it does.
/// </summary>
public void CheckNewIdentity(EntityUid uid)
{
var name = Identity.Name(uid, EntityManager);
var xform = Transform(uid);
var station = _station.GetStationInMap(xform.MapID);

if (station != null && _stationRecords.GetRecordByName(station.Value, name) is { } id)
{
if (_stationRecords.TryGetRecord<CriminalRecord>(new StationRecordKey(id, station.Value),
out var record))
{
if (record.Status != SecurityStatus.None)
{
SetCriminalIcon(name, record.Status, uid);
return;
}
}
}
RemComp<CriminalRecordComponent>(uid);
}
}
28 changes: 15 additions & 13 deletions Content.Server/IdentityManagement/IdentitySystem.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Content.Server.Access.Systems;
using Content.Server.Administration.Logs;
using Content.Server.CriminalRecords.Systems;
using Content.Server.Humanoid;
using Content.Shared.Clothing;
using Content.Shared.Database;
Expand All @@ -25,6 +26,7 @@ public class IdentitySystem : SharedIdentitySystem
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!;
[Dependency] private readonly CriminalRecordsConsoleSystem _criminalRecordsConsole = default!;

private HashSet<EntityUid> _queuedIdentityUpdates = new();

Expand Down Expand Up @@ -107,7 +109,9 @@ private void UpdateIdentityInfo(EntityUid uid, IdentityComponent identity)
_metaData.SetEntityName(ident, name);

_adminLog.Add(LogType.Identity, LogImpact.Medium, $"{ToPrettyString(uid)} changed identity to {name}");
RaiseLocalEvent(new IdentityChangedEvent(uid, ident));
var identityChangedEvent = new IdentityChangedEvent(uid, ident);
RaiseLocalEvent(uid, ref identityChangedEvent);
SetIdentityCriminalIcon(uid);
}

private string GetIdentityName(EntityUid target, IdentityRepresentation representation)
Expand All @@ -118,6 +122,16 @@ private string GetIdentityName(EntityUid target, IdentityRepresentation represen
return representation.ToStringKnown(!ev.Cancelled);
}

/// <summary>
/// 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.
/// </summary>
private void SetIdentityCriminalIcon(EntityUid uid)
{
_criminalRecordsConsole.CheckNewIdentity(uid);
}

/// <summary>
/// Gets an 'identity representation' of an entity, with their true name being the entity name
/// and their 'presumed name' and 'presumed job' being the name/job on their ID card, if they have one.
Expand Down Expand Up @@ -159,15 +173,3 @@ private IdentityRepresentation GetIdentityRepresentation(EntityUid target,

#endregion
}

public sealed class IdentityChangedEvent : EntityEventArgs
{
public EntityUid CharacterEntity;
public EntityUid IdentityEntity;

public IdentityChangedEvent(EntityUid characterEntity, EntityUid identityEntity)
{
CharacterEntity = characterEntity;
IdentityEntity = identityEntity;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,52 @@
using Content.Shared.IdentityManagement;
using Content.Shared.IdentityManagement.Components;
using Content.Shared.Security;
using Content.Shared.Security.Components;

namespace Content.Shared.CriminalRecords.Systems;

/// <summary>
/// Nothing is predicted just exists for access.
/// </summary>
public abstract class SharedCriminalRecordsConsoleSystem : EntitySystem
{
/// <summary>
/// Any entity that has a 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.
/// </summary>
public void UpdateCriminalIdentity(string name, SecurityStatus status)
{
var query = EntityQueryEnumerator<IdentityComponent>();

while (query.MoveNext(out var uid, out var identity))
{
if (!Identity.Name(uid, EntityManager).Equals(name))
continue;

if (status == SecurityStatus.None)
RemComp<CriminalRecordComponent>(uid);
else
SetCriminalIcon(name, status, uid);
}
}

/// <summary>
/// Decides the icon that should be displayed on the entity based on the security status
/// </summary>
public void SetCriminalIcon(string name, SecurityStatus status, EntityUid characterUid)
{
EnsureComp<CriminalRecordComponent>(characterUid, out var record);

var previousIcon = record.StatusIcon;

record.StatusIcon = status switch
{
SecurityStatus.Paroled => "SecurityIconParoled",
SecurityStatus.Wanted => "SecurityIconWanted",
SecurityStatus.Detained => "SecurityIconIncarcerated",
SecurityStatus.Discharged => "SecurityIconDischarged",
SecurityStatus.Suspected => "SecurityIconSuspected",
_ => record.StatusIcon
};

if(previousIcon != record.StatusIcon)
Dirty(characterUid, record);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Content.Shared.Humanoid.Prototypes;
using Robust.Shared.Containers;
using Robust.Shared.Containers;
using Robust.Shared.Enums;

namespace Content.Shared.IdentityManagement.Components;
Expand Down
5 changes: 5 additions & 0 deletions Content.Shared/IdentityManagement/SharedIdentitySystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@ private void OnMaskToggled(Entity<IdentityBlockerComponent> ent, ref ItemMaskTog
ent.Comp.Enabled = !args.IsToggled;
}
}
/// <summary>
/// Gets called whenever an entity changes their identity.
/// </summary>
[ByRefEvent]
public record struct IdentityChangedEvent(EntityUid CharacterEntity, EntityUid IdentityEntity);
15 changes: 15 additions & 0 deletions Content.Shared/Security/Components/CriminalRecordComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Content.Shared.StatusIcon;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;

namespace Content.Shared.Security.Components;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class CriminalRecordComponent : Component
{
/// <summary>
/// The icon that should be displayed based on the criminal status of the entity.
/// </summary>
[DataField, AutoNetworkedField]
public ProtoId<StatusIconPrototype> StatusIcon = "SecurityIconWanted";
}
8 changes: 7 additions & 1 deletion Content.Shared/Security/SecurityStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
/// Status used in Criminal Records.
///
/// None - the default value
/// Suspected - the person is suspected of doing something illegal
/// Wanted - the person is being wanted by security
/// Detained - the person is detained by security
/// Paroled - the person is on parole
/// Discharged - the person has been released from prison
/// </summary>
public enum SecurityStatus : byte
{
None,
Suspected,
Wanted,
Detained
Detained,
Paroled,
Discharged
}
Loading

0 comments on commit 8b8fcd4

Please sign in to comment.