1
0

AnomalySystem.Vessel.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using Content.Server.Anomaly.Components;
  2. using Content.Server.Power.EntitySystems;
  3. using Content.Shared.Anomaly;
  4. using Content.Shared.Anomaly.Components;
  5. using Content.Shared.Examine;
  6. using Content.Shared.Interaction;
  7. using Content.Shared.Research.Components;
  8. namespace Content.Server.Anomaly;
  9. /// <summary>
  10. /// This handles anomalous vessel as well as
  11. /// the calculations for how many points they
  12. /// should produce.
  13. /// </summary>
  14. public sealed partial class AnomalySystem
  15. {
  16. private void InitializeVessel()
  17. {
  18. SubscribeLocalEvent<AnomalyVesselComponent, ComponentShutdown>(OnVesselShutdown);
  19. SubscribeLocalEvent<AnomalyVesselComponent, MapInitEvent>(OnVesselMapInit);
  20. SubscribeLocalEvent<AnomalyVesselComponent, InteractUsingEvent>(OnVesselInteractUsing);
  21. SubscribeLocalEvent<AnomalyVesselComponent, ExaminedEvent>(OnExamined);
  22. SubscribeLocalEvent<AnomalyVesselComponent, ResearchServerGetPointsPerSecondEvent>(OnVesselGetPointsPerSecond);
  23. SubscribeLocalEvent<AnomalyShutdownEvent>(OnShutdown);
  24. SubscribeLocalEvent<AnomalyStabilityChangedEvent>(OnStabilityChanged);
  25. }
  26. private void OnStabilityChanged(ref AnomalyStabilityChangedEvent args)
  27. {
  28. OnVesselAnomalyStabilityChanged(ref args);
  29. OnScannerAnomalyStabilityChanged(ref args);
  30. }
  31. private void OnShutdown(ref AnomalyShutdownEvent args)
  32. {
  33. OnVesselAnomalyShutdown(ref args);
  34. OnScannerAnomalyShutdown(ref args);
  35. }
  36. private void OnExamined(EntityUid uid, AnomalyVesselComponent component, ExaminedEvent args)
  37. {
  38. if (!args.IsInDetailsRange)
  39. return;
  40. args.PushText(component.Anomaly == null
  41. ? Loc.GetString("anomaly-vessel-component-not-assigned")
  42. : Loc.GetString("anomaly-vessel-component-assigned"));
  43. }
  44. private void OnVesselShutdown(EntityUid uid, AnomalyVesselComponent component, ComponentShutdown args)
  45. {
  46. if (component.Anomaly is not { } anomaly)
  47. return;
  48. if (!TryComp<AnomalyComponent>(anomaly, out var anomalyComp))
  49. return;
  50. anomalyComp.ConnectedVessel = null;
  51. }
  52. private void OnVesselMapInit(EntityUid uid, AnomalyVesselComponent component, MapInitEvent args)
  53. {
  54. UpdateVesselAppearance(uid, component);
  55. }
  56. private void OnVesselInteractUsing(EntityUid uid, AnomalyVesselComponent component, InteractUsingEvent args)
  57. {
  58. if (component.Anomaly != null ||
  59. !TryComp<AnomalyScannerComponent>(args.Used, out var scanner) ||
  60. scanner.ScannedAnomaly is not { } anomaly)
  61. {
  62. return;
  63. }
  64. if (!TryComp<AnomalyComponent>(anomaly, out var anomalyComponent) || anomalyComponent.ConnectedVessel != null)
  65. return;
  66. component.Anomaly = scanner.ScannedAnomaly;
  67. anomalyComponent.ConnectedVessel = uid;
  68. _radiation.SetSourceEnabled(uid, true);
  69. UpdateVesselAppearance(uid, component);
  70. Popup.PopupEntity(Loc.GetString("anomaly-vessel-component-anomaly-assigned"), uid);
  71. }
  72. private void OnVesselGetPointsPerSecond(EntityUid uid, AnomalyVesselComponent component, ref ResearchServerGetPointsPerSecondEvent args)
  73. {
  74. if (!this.IsPowered(uid, EntityManager) || component.Anomaly is not {} anomaly)
  75. return;
  76. args.Points += (int) (GetAnomalyPointValue(anomaly) * component.PointMultiplier);
  77. }
  78. private void OnVesselAnomalyShutdown(ref AnomalyShutdownEvent args)
  79. {
  80. var query = EntityQueryEnumerator<AnomalyVesselComponent>();
  81. while (query.MoveNext(out var ent, out var component))
  82. {
  83. if (args.Anomaly != component.Anomaly)
  84. continue;
  85. component.Anomaly = null;
  86. UpdateVesselAppearance(ent, component);
  87. _radiation.SetSourceEnabled(ent, false);
  88. if (!args.Supercritical)
  89. continue;
  90. _explosion.TriggerExplosive(ent);
  91. }
  92. }
  93. private void OnVesselAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args)
  94. {
  95. var query = EntityQueryEnumerator<AnomalyVesselComponent>();
  96. while (query.MoveNext(out var ent, out var component))
  97. {
  98. if (args.Anomaly != component.Anomaly)
  99. continue;
  100. UpdateVesselAppearance(ent, component);
  101. }
  102. }
  103. /// <summary>
  104. /// Updates the appearance of an anomaly vessel
  105. /// based on whether or not it has an anomaly
  106. /// </summary>
  107. /// <param name="uid"></param>
  108. /// <param name="component"></param>
  109. public void UpdateVesselAppearance(EntityUid uid, AnomalyVesselComponent? component = null)
  110. {
  111. if (!Resolve(uid, ref component))
  112. return;
  113. var on = component.Anomaly != null;
  114. if (!TryComp<AppearanceComponent>(uid, out var appearanceComponent))
  115. return;
  116. Appearance.SetData(uid, AnomalyVesselVisuals.HasAnomaly, on, appearanceComponent);
  117. if (_pointLight.TryGetLight(uid, out var pointLightComponent))
  118. _pointLight.SetEnabled(uid, on, pointLightComponent);
  119. // arbitrary value for the generic visualizer to use.
  120. // i didn't feel like making an enum for this.
  121. var value = 1;
  122. if (TryComp<AnomalyComponent>(component.Anomaly, out var anomalyComp))
  123. {
  124. if (anomalyComp.Stability <= anomalyComp.DecayThreshold)
  125. {
  126. value = 2;
  127. }
  128. else if (anomalyComp.Stability >= anomalyComp.GrowthThreshold)
  129. {
  130. value = 3;
  131. }
  132. }
  133. Appearance.SetData(uid, AnomalyVesselVisuals.AnomalyState, value, appearanceComponent);
  134. _ambient.SetAmbience(uid, on);
  135. }
  136. private void UpdateVessels()
  137. {
  138. var query = EntityQueryEnumerator<AnomalyVesselComponent>();
  139. while (query.MoveNext(out var vesselEnt, out var vessel))
  140. {
  141. if (vessel.Anomaly is not { } anomUid)
  142. continue;
  143. if (!TryComp<AnomalyComponent>(anomUid, out var anomaly))
  144. continue;
  145. if (Timing.CurTime < vessel.NextBeep)
  146. continue;
  147. // a lerp between the max and min values for each threshold.
  148. // longer beeps that get shorter as the anomaly gets more extreme
  149. float timerPercentage;
  150. if (anomaly.Stability <= anomaly.DecayThreshold)
  151. timerPercentage = (anomaly.DecayThreshold - anomaly.Stability) / anomaly.DecayThreshold;
  152. else if (anomaly.Stability >= anomaly.GrowthThreshold)
  153. timerPercentage = (anomaly.Stability - anomaly.GrowthThreshold) / (1 - anomaly.GrowthThreshold);
  154. else //it's not unstable
  155. continue;
  156. Audio.PlayPvs(vessel.BeepSound, vesselEnt);
  157. var beepInterval = (vessel.MaxBeepInterval - vessel.MinBeepInterval) * (1 - timerPercentage) + vessel.MinBeepInterval;
  158. vessel.NextBeep = beepInterval + Timing.CurTime;
  159. }
  160. }
  161. }