CriminalRecordsSystem.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. using System.Linq;
  2. using Content.Server.CartridgeLoader;
  3. using Content.Server.CartridgeLoader.Cartridges;
  4. using Content.Server.StationRecords.Systems;
  5. using Content.Shared.CriminalRecords;
  6. using Content.Shared.CriminalRecords.Systems;
  7. using Content.Shared.Security;
  8. using Content.Shared.StationRecords;
  9. using Content.Server.GameTicking;
  10. using Content.Server.Station.Systems;
  11. using Content.Shared.CartridgeLoader;
  12. using Content.Shared.CartridgeLoader.Cartridges;
  13. namespace Content.Server.CriminalRecords.Systems;
  14. /// <summary>
  15. /// Criminal records
  16. ///
  17. /// Criminal Records inherit Station Records' core and add role-playing tools for Security:
  18. /// - Ability to track a person's status (Detained/Wanted/None)
  19. /// - See security officers' actions in Criminal Records in the radio
  20. /// - See reasons for any action with no need to ask the officer personally
  21. /// </summary>
  22. public sealed class CriminalRecordsSystem : SharedCriminalRecordsSystem
  23. {
  24. [Dependency] private readonly GameTicker _ticker = default!;
  25. [Dependency] private readonly StationRecordsSystem _records = default!;
  26. [Dependency] private readonly StationSystem _station = default!;
  27. [Dependency] private readonly CartridgeLoaderSystem _cartridge = default!;
  28. public override void Initialize()
  29. {
  30. base.Initialize();
  31. SubscribeLocalEvent<AfterGeneralRecordCreatedEvent>(OnGeneralRecordCreated);
  32. SubscribeLocalEvent<WantedListCartridgeComponent, CriminalRecordChangedEvent>(OnRecordChanged);
  33. SubscribeLocalEvent<WantedListCartridgeComponent, CartridgeUiReadyEvent>(OnCartridgeUiReady);
  34. SubscribeLocalEvent<WantedListCartridgeComponent, CriminalHistoryAddedEvent>(OnHistoryAdded);
  35. SubscribeLocalEvent<WantedListCartridgeComponent, CriminalHistoryRemovedEvent>(OnHistoryRemoved);
  36. }
  37. private void OnGeneralRecordCreated(AfterGeneralRecordCreatedEvent ev)
  38. {
  39. _records.AddRecordEntry(ev.Key, new CriminalRecord());
  40. _records.Synchronize(ev.Key);
  41. }
  42. /// <summary>
  43. /// Tries to change the status of the record found by the StationRecordKey.
  44. /// Reason should only be passed if status is Wanted, nullability isn't checked.
  45. /// </summary>
  46. /// <returns>True if the status is changed, false if not</returns>
  47. public bool TryChangeStatus(StationRecordKey key, SecurityStatus status, string? reason, string? initiatorName = null)
  48. {
  49. // don't do anything if its the same status
  50. if (!_records.TryGetRecord<CriminalRecord>(key, out var record)
  51. || status == record.Status)
  52. return false;
  53. OverwriteStatus(key, record, status, reason, initiatorName);
  54. return true;
  55. }
  56. /// <summary>
  57. /// Sets the status without checking previous status or reason nullability.
  58. /// </summary>
  59. public void OverwriteStatus(StationRecordKey key, CriminalRecord record, SecurityStatus status, string? reason, string? initiatorName = null)
  60. {
  61. record.Status = status;
  62. record.Reason = reason;
  63. record.InitiatorName = initiatorName;
  64. var name = _records.RecordName(key);
  65. if (name != string.Empty)
  66. UpdateCriminalIdentity(name, status);
  67. _records.Synchronize(key);
  68. var args = new CriminalRecordChangedEvent(record);
  69. var query = EntityQueryEnumerator<WantedListCartridgeComponent>();
  70. while (query.MoveNext(out var readerUid, out _))
  71. {
  72. RaiseLocalEvent(readerUid, ref args);
  73. }
  74. }
  75. /// <summary>
  76. /// Tries to add a history entry to a criminal record.
  77. /// </summary>
  78. /// <returns>True if adding succeeded, false if not</returns>
  79. public bool TryAddHistory(StationRecordKey key, CrimeHistory entry)
  80. {
  81. if (!_records.TryGetRecord<CriminalRecord>(key, out var record))
  82. return false;
  83. record.History.Add(entry);
  84. var args = new CriminalHistoryAddedEvent(entry);
  85. var query = EntityQueryEnumerator<WantedListCartridgeComponent>();
  86. while (query.MoveNext(out var readerUid, out _))
  87. {
  88. RaiseLocalEvent(readerUid, ref args);
  89. }
  90. return true;
  91. }
  92. /// <summary>
  93. /// Creates and tries to add a history entry using the current time.
  94. /// </summary>
  95. public bool TryAddHistory(StationRecordKey key, string line, string? initiatorName = null)
  96. {
  97. var entry = new CrimeHistory(_ticker.RoundDuration(), line, initiatorName);
  98. return TryAddHistory(key, entry);
  99. }
  100. /// <summary>
  101. /// Tries to delete a sepcific line of history from a criminal record, by index.
  102. /// </summary>
  103. /// <returns>True if the line was removed, false if not</returns>
  104. public bool TryDeleteHistory(StationRecordKey key, uint index)
  105. {
  106. if (!_records.TryGetRecord<CriminalRecord>(key, out var record))
  107. return false;
  108. if (index >= record.History.Count)
  109. return false;
  110. var history = record.History[(int)index];
  111. record.History.RemoveAt((int) index);
  112. var args = new CriminalHistoryRemovedEvent(history);
  113. var query = EntityQueryEnumerator<WantedListCartridgeComponent>();
  114. while (query.MoveNext(out var readerUid, out _))
  115. {
  116. RaiseLocalEvent(readerUid, ref args);
  117. }
  118. return true;
  119. }
  120. private void OnRecordChanged(Entity<WantedListCartridgeComponent> ent, ref CriminalRecordChangedEvent args) =>
  121. StateChanged(ent);
  122. private void OnHistoryAdded(Entity<WantedListCartridgeComponent> ent, ref CriminalHistoryAddedEvent args) =>
  123. StateChanged(ent);
  124. private void OnHistoryRemoved(Entity<WantedListCartridgeComponent> ent, ref CriminalHistoryRemovedEvent args) =>
  125. StateChanged(ent);
  126. private void StateChanged(Entity<WantedListCartridgeComponent> ent)
  127. {
  128. if (Comp<CartridgeComponent>(ent).LoaderUid is not { } loaderUid)
  129. return;
  130. UpdateReaderUi(ent, loaderUid);
  131. }
  132. private void OnCartridgeUiReady(Entity<WantedListCartridgeComponent> ent, ref CartridgeUiReadyEvent args)
  133. {
  134. UpdateReaderUi(ent, args.Loader);
  135. }
  136. private void UpdateReaderUi(Entity<WantedListCartridgeComponent> ent, EntityUid loaderUid)
  137. {
  138. if (_station.GetOwningStation(ent) is not { } station)
  139. return;
  140. var records = _records.GetRecordsOfType<CriminalRecord>(station)
  141. .Where(cr => cr.Item2.Status is not SecurityStatus.None || cr.Item2.History.Count > 0)
  142. .Select(cr =>
  143. {
  144. var (i, r) = cr;
  145. var key = new StationRecordKey(i, station);
  146. // Hopefully it will work smoothly.....
  147. _records.TryGetRecord(key, out GeneralStationRecord? generalRecord);
  148. return new WantedRecord(generalRecord!, r.Status, r.Reason, r.InitiatorName, r.History);
  149. });
  150. var state = new WantedListUiState(records.ToList());
  151. _cartridge.UpdateCartridgeUiState(loaderUid, state);
  152. }
  153. }