AnomalySystem.Scanner.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. using Content.Server.Anomaly.Components;
  2. using Content.Shared.Anomaly;
  3. using Content.Shared.Anomaly.Components;
  4. using Content.Shared.DoAfter;
  5. using Content.Shared.Interaction;
  6. using Robust.Shared.Player;
  7. using Robust.Shared.Utility;
  8. namespace Content.Server.Anomaly;
  9. /// <summary>
  10. /// This handles the anomaly scanner and it's UI updates.
  11. /// </summary>
  12. public sealed partial class AnomalySystem
  13. {
  14. private void InitializeScanner()
  15. {
  16. SubscribeLocalEvent<AnomalyScannerComponent, BoundUIOpenedEvent>(OnScannerUiOpened);
  17. SubscribeLocalEvent<AnomalyScannerComponent, AfterInteractEvent>(OnScannerAfterInteract);
  18. SubscribeLocalEvent<AnomalyScannerComponent, ScannerDoAfterEvent>(OnDoAfter);
  19. SubscribeLocalEvent<AnomalySeverityChangedEvent>(OnScannerAnomalySeverityChanged);
  20. SubscribeLocalEvent<AnomalyHealthChangedEvent>(OnScannerAnomalyHealthChanged);
  21. SubscribeLocalEvent<AnomalyBehaviorChangedEvent>(OnScannerAnomalyBehaviorChanged);
  22. }
  23. private void OnScannerAnomalyShutdown(ref AnomalyShutdownEvent args)
  24. {
  25. var query = EntityQueryEnumerator<AnomalyScannerComponent>();
  26. while (query.MoveNext(out var uid, out var component))
  27. {
  28. if (component.ScannedAnomaly != args.Anomaly)
  29. continue;
  30. _ui.CloseUi(uid, AnomalyScannerUiKey.Key);
  31. }
  32. }
  33. private void OnScannerAnomalySeverityChanged(ref AnomalySeverityChangedEvent args)
  34. {
  35. var query = EntityQueryEnumerator<AnomalyScannerComponent>();
  36. while (query.MoveNext(out var uid, out var component))
  37. {
  38. if (component.ScannedAnomaly != args.Anomaly)
  39. continue;
  40. UpdateScannerUi(uid, component);
  41. }
  42. }
  43. private void OnScannerAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
  44. {
  45. var query = EntityQueryEnumerator<AnomalyScannerComponent>();
  46. while (query.MoveNext(out var uid, out var component))
  47. {
  48. if (component.ScannedAnomaly != args.Anomaly)
  49. continue;
  50. UpdateScannerUi(uid, component);
  51. }
  52. }
  53. private void OnScannerAnomalyHealthChanged(ref AnomalyHealthChangedEvent args)
  54. {
  55. var query = EntityQueryEnumerator<AnomalyScannerComponent>();
  56. while (query.MoveNext(out var uid, out var component))
  57. {
  58. if (component.ScannedAnomaly != args.Anomaly)
  59. continue;
  60. UpdateScannerUi(uid, component);
  61. }
  62. }
  63. private void OnScannerAnomalyBehaviorChanged(ref AnomalyBehaviorChangedEvent args)
  64. {
  65. var query = EntityQueryEnumerator<AnomalyScannerComponent>();
  66. while (query.MoveNext(out var uid, out var component))
  67. {
  68. if (component.ScannedAnomaly != args.Anomaly)
  69. continue;
  70. UpdateScannerUi(uid, component);
  71. }
  72. }
  73. private void OnScannerUiOpened(EntityUid uid, AnomalyScannerComponent component, BoundUIOpenedEvent args)
  74. {
  75. UpdateScannerUi(uid, component);
  76. }
  77. private void OnScannerAfterInteract(EntityUid uid, AnomalyScannerComponent component, AfterInteractEvent args)
  78. {
  79. if (args.Target is not { } target)
  80. return;
  81. if (!HasComp<AnomalyComponent>(target))
  82. return;
  83. if (!args.CanReach)
  84. return;
  85. _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.ScanDoAfterDuration, new ScannerDoAfterEvent(), uid, target: target, used: uid)
  86. {
  87. DistanceThreshold = 2f
  88. });
  89. }
  90. private void OnDoAfter(EntityUid uid, AnomalyScannerComponent component, DoAfterEvent args)
  91. {
  92. if (args.Cancelled || args.Handled || args.Args.Target == null)
  93. return;
  94. Audio.PlayPvs(component.CompleteSound, uid);
  95. Popup.PopupEntity(Loc.GetString("anomaly-scanner-component-scan-complete"), uid);
  96. UpdateScannerWithNewAnomaly(uid, args.Args.Target.Value, component);
  97. _ui.OpenUi(uid, AnomalyScannerUiKey.Key, args.User);
  98. args.Handled = true;
  99. }
  100. public void UpdateScannerUi(EntityUid uid, AnomalyScannerComponent? component = null)
  101. {
  102. if (!Resolve(uid, ref component))
  103. return;
  104. TimeSpan? nextPulse = null;
  105. if (TryComp<AnomalyComponent>(component.ScannedAnomaly, out var anomalyComponent))
  106. nextPulse = anomalyComponent.NextPulseTime;
  107. var state = new AnomalyScannerUserInterfaceState(GetScannerMessage(component), nextPulse);
  108. _ui.SetUiState(uid, AnomalyScannerUiKey.Key, state);
  109. }
  110. public void UpdateScannerWithNewAnomaly(EntityUid scanner, EntityUid anomaly, AnomalyScannerComponent? scannerComp = null, AnomalyComponent? anomalyComp = null)
  111. {
  112. if (!Resolve(scanner, ref scannerComp) || !Resolve(anomaly, ref anomalyComp))
  113. return;
  114. scannerComp.ScannedAnomaly = anomaly;
  115. UpdateScannerUi(scanner, scannerComp);
  116. }
  117. public FormattedMessage GetScannerMessage(AnomalyScannerComponent component)
  118. {
  119. var msg = new FormattedMessage();
  120. if (component.ScannedAnomaly is not { } anomaly || !TryComp<AnomalyComponent>(anomaly, out var anomalyComp))
  121. {
  122. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-no-anomaly"));
  123. return msg;
  124. }
  125. TryComp<SecretDataAnomalyComponent>(anomaly, out var secret);
  126. //Severity
  127. if (secret != null && secret.Secret.Contains(AnomalySecretData.Severity))
  128. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage-unknown"));
  129. else
  130. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage", ("percent", anomalyComp.Severity.ToString("P"))));
  131. msg.PushNewline();
  132. //Stability
  133. if (secret != null && secret.Secret.Contains(AnomalySecretData.Stability))
  134. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-stability-unknown"));
  135. else
  136. {
  137. string stateLoc;
  138. if (anomalyComp.Stability < anomalyComp.DecayThreshold)
  139. stateLoc = Loc.GetString("anomaly-scanner-stability-low");
  140. else if (anomalyComp.Stability > anomalyComp.GrowthThreshold)
  141. stateLoc = Loc.GetString("anomaly-scanner-stability-high");
  142. else
  143. stateLoc = Loc.GetString("anomaly-scanner-stability-medium");
  144. msg.AddMarkupOrThrow(stateLoc);
  145. }
  146. msg.PushNewline();
  147. //Point output
  148. if (secret != null && secret.Secret.Contains(AnomalySecretData.OutputPoint))
  149. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output-unknown"));
  150. else
  151. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output", ("point", GetAnomalyPointValue(anomaly, anomalyComp))));
  152. msg.PushNewline();
  153. msg.PushNewline();
  154. //Particles title
  155. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-readout"));
  156. msg.PushNewline();
  157. //Danger
  158. if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleDanger))
  159. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger-unknown"));
  160. else
  161. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger", ("type", GetParticleLocale(anomalyComp.SeverityParticleType))));
  162. msg.PushNewline();
  163. //Unstable
  164. if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleUnstable))
  165. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable-unknown"));
  166. else
  167. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable", ("type", GetParticleLocale(anomalyComp.DestabilizingParticleType))));
  168. msg.PushNewline();
  169. //Containment
  170. if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleContainment))
  171. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment-unknown"));
  172. else
  173. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment", ("type", GetParticleLocale(anomalyComp.WeakeningParticleType))));
  174. msg.PushNewline();
  175. //Transformation
  176. if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleTransformation))
  177. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation-unknown"));
  178. else
  179. msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation", ("type", GetParticleLocale(anomalyComp.TransformationParticleType))));
  180. //Behavior
  181. msg.PushNewline();
  182. msg.PushNewline();
  183. msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-title"));
  184. msg.PushNewline();
  185. if (secret != null && secret.Secret.Contains(AnomalySecretData.Behavior))
  186. msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-unknown"));
  187. else
  188. {
  189. if (anomalyComp.CurrentBehavior != null)
  190. {
  191. var behavior = _prototype.Index(anomalyComp.CurrentBehavior.Value);
  192. msg.AddMarkupOrThrow("- " + Loc.GetString(behavior.Description));
  193. msg.PushNewline();
  194. var mod = Math.Floor((behavior.EarnPointModifier) * 100);
  195. msg.AddMarkupOrThrow("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod)));
  196. }
  197. else
  198. {
  199. msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-balanced"));
  200. }
  201. }
  202. //The timer at the end here is actually added in the ui itself.
  203. return msg;
  204. }
  205. }