InnerBodyAnomalySystem.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using Content.Server.Administration.Logs;
  2. using Content.Server.Body.Systems;
  3. using Content.Server.Chat.Managers;
  4. using Content.Server.Jittering;
  5. using Content.Server.Mind;
  6. using Content.Server.Stunnable;
  7. using Content.Shared.Anomaly;
  8. using Content.Shared.Anomaly.Components;
  9. using Content.Shared.Anomaly.Effects;
  10. using Content.Shared.Body.Components;
  11. using Content.Shared.Chat;
  12. using Content.Shared.Database;
  13. using Content.Shared.Mobs;
  14. using Content.Shared.Popups;
  15. using Content.Shared.Whitelist;
  16. using Robust.Shared.Audio.Systems;
  17. using Robust.Shared.Physics.Events;
  18. using Robust.Shared.Prototypes;
  19. namespace Content.Server.Anomaly.Effects;
  20. public sealed class InnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
  21. {
  22. [Dependency] private readonly IAdminLogManager _adminLog = default!;
  23. [Dependency] private readonly AnomalySystem _anomaly = default!;
  24. [Dependency] private readonly SharedAudioSystem _audio = default!;
  25. [Dependency] private readonly BodySystem _body = default!;
  26. [Dependency] private readonly IChatManager _chat = default!;
  27. [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
  28. [Dependency] private readonly JitteringSystem _jitter = default!;
  29. [Dependency] private readonly MindSystem _mind = default!;
  30. [Dependency] private readonly SharedPopupSystem _popup = default!;
  31. [Dependency] private readonly IPrototypeManager _proto = default!;
  32. [Dependency] private readonly StunSystem _stun = default!;
  33. private readonly Color _messageColor = Color.FromSrgb(new Color(201, 22, 94));
  34. public override void Initialize()
  35. {
  36. base.Initialize();
  37. SubscribeLocalEvent<InnerBodyAnomalyInjectorComponent, StartCollideEvent>(OnStartCollideInjector);
  38. SubscribeLocalEvent<InnerBodyAnomalyComponent, MapInitEvent>(OnMapInit);
  39. SubscribeLocalEvent<InnerBodyAnomalyComponent, ComponentShutdown>(OnCompShutdown);
  40. SubscribeLocalEvent<InnerBodyAnomalyComponent, AnomalyPulseEvent>(OnAnomalyPulse);
  41. SubscribeLocalEvent<InnerBodyAnomalyComponent, AnomalyShutdownEvent>(OnAnomalyShutdown);
  42. SubscribeLocalEvent<InnerBodyAnomalyComponent, AnomalySupercriticalEvent>(OnAnomalySupercritical);
  43. SubscribeLocalEvent<InnerBodyAnomalyComponent, AnomalySeverityChangedEvent>(OnSeverityChanged);
  44. SubscribeLocalEvent<InnerBodyAnomalyComponent, MobStateChangedEvent>(OnMobStateChanged);
  45. SubscribeLocalEvent<AnomalyComponent, ActionAnomalyPulseEvent>(OnActionPulse);
  46. }
  47. private void OnActionPulse(Entity<AnomalyComponent> ent, ref ActionAnomalyPulseEvent args)
  48. {
  49. if (args.Handled)
  50. return;
  51. _anomaly.DoAnomalyPulse(ent, ent.Comp);
  52. args.Handled = true;
  53. }
  54. private void OnStartCollideInjector(Entity<InnerBodyAnomalyInjectorComponent> ent, ref StartCollideEvent args)
  55. {
  56. if (ent.Comp.Whitelist is not null && !_whitelist.IsValid(ent.Comp.Whitelist, args.OtherEntity))
  57. return;
  58. if (TryComp<InnerBodyAnomalyComponent>(args.OtherEntity, out var innerAnom) && innerAnom.Injected)
  59. return;
  60. if (!_mind.TryGetMind(args.OtherEntity, out _, out var mindComponent))
  61. return;
  62. EntityManager.AddComponents(args.OtherEntity, ent.Comp.InjectionComponents);
  63. QueueDel(ent);
  64. }
  65. private void OnMapInit(Entity<InnerBodyAnomalyComponent> ent, ref MapInitEvent args)
  66. {
  67. AddAnomalyToBody(ent);
  68. }
  69. private void AddAnomalyToBody(Entity<InnerBodyAnomalyComponent> ent)
  70. {
  71. if (!_proto.TryIndex(ent.Comp.InjectionProto, out var injectedAnom))
  72. return;
  73. if (ent.Comp.Injected)
  74. return;
  75. ent.Comp.Injected = true;
  76. EntityManager.AddComponents(ent, injectedAnom.Components);
  77. _stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true);
  78. _jitter.DoJitter(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true);
  79. if (ent.Comp.StartSound is not null)
  80. _audio.PlayPvs(ent.Comp.StartSound, ent);
  81. if (ent.Comp.StartMessage is not null &&
  82. _mind.TryGetMind(ent, out _, out var mindComponent) &&
  83. mindComponent.Session != null)
  84. {
  85. var message = Loc.GetString(ent.Comp.StartMessage);
  86. var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
  87. _chat.ChatMessageToOne(ChatChannel.Server,
  88. message,
  89. wrappedMessage,
  90. default,
  91. false,
  92. mindComponent.Session.Channel,
  93. _messageColor);
  94. _popup.PopupEntity(message, ent, ent, PopupType.MediumCaution);
  95. _adminLog.Add(LogType.Anomaly,LogImpact.Extreme,$"{ToPrettyString(ent)} became anomaly host.");
  96. }
  97. Dirty(ent);
  98. }
  99. private void OnAnomalyPulse(Entity<InnerBodyAnomalyComponent> ent, ref AnomalyPulseEvent args)
  100. {
  101. _stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration / 2 * args.Severity), true);
  102. _jitter.DoJitter(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration / 2 * args.Severity), true);
  103. }
  104. private void OnAnomalySupercritical(Entity<InnerBodyAnomalyComponent> ent, ref AnomalySupercriticalEvent args)
  105. {
  106. if (!TryComp<BodyComponent>(ent, out var body))
  107. return;
  108. _body.GibBody(ent, true, body, splatModifier: 5f);
  109. }
  110. private void OnSeverityChanged(Entity<InnerBodyAnomalyComponent> ent, ref AnomalySeverityChangedEvent args)
  111. {
  112. if (!_mind.TryGetMind(ent, out _, out var mindComponent) || mindComponent.Session == null)
  113. return;
  114. var message = string.Empty;
  115. if (args.Severity >= 0.5 && ent.Comp.LastSeverityInformed < 0.5)
  116. {
  117. ent.Comp.LastSeverityInformed = 0.5f;
  118. message = Loc.GetString("inner-anomaly-severity-info-50");
  119. }
  120. if (args.Severity >= 0.75 && ent.Comp.LastSeverityInformed < 0.75)
  121. {
  122. ent.Comp.LastSeverityInformed = 0.75f;
  123. message = Loc.GetString("inner-anomaly-severity-info-75");
  124. }
  125. if (args.Severity >= 0.9 && ent.Comp.LastSeverityInformed < 0.9)
  126. {
  127. ent.Comp.LastSeverityInformed = 0.9f;
  128. message = Loc.GetString("inner-anomaly-severity-info-90");
  129. }
  130. if (args.Severity >= 1 && ent.Comp.LastSeverityInformed < 1)
  131. {
  132. ent.Comp.LastSeverityInformed = 1f;
  133. message = Loc.GetString("inner-anomaly-severity-info-100");
  134. }
  135. if (message == string.Empty)
  136. return;
  137. var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
  138. _chat.ChatMessageToOne(ChatChannel.Server,
  139. message,
  140. wrappedMessage,
  141. default,
  142. false,
  143. mindComponent.Session.Channel,
  144. _messageColor);
  145. _popup.PopupEntity(message, ent, ent, PopupType.MediumCaution);
  146. }
  147. private void OnMobStateChanged(Entity<InnerBodyAnomalyComponent> ent, ref MobStateChangedEvent args)
  148. {
  149. if (args.NewMobState != MobState.Dead)
  150. return;
  151. var ev = new BeforeRemoveAnomalyOnDeathEvent();
  152. RaiseLocalEvent(args.Target, ref ev);
  153. if (ev.Cancelled)
  154. return;
  155. _anomaly.ChangeAnomalyHealth(ent, -2); //Shutdown it
  156. }
  157. private void OnAnomalyShutdown(Entity<InnerBodyAnomalyComponent> ent, ref AnomalyShutdownEvent args)
  158. {
  159. RemoveAnomalyFromBody(ent);
  160. RemCompDeferred<InnerBodyAnomalyComponent>(ent);
  161. }
  162. private void OnCompShutdown(Entity<InnerBodyAnomalyComponent> ent, ref ComponentShutdown args)
  163. {
  164. RemoveAnomalyFromBody(ent);
  165. }
  166. private void RemoveAnomalyFromBody(Entity<InnerBodyAnomalyComponent> ent)
  167. {
  168. if (!ent.Comp.Injected)
  169. return;
  170. if (_proto.TryIndex(ent.Comp.InjectionProto, out var injectedAnom))
  171. EntityManager.RemoveComponents(ent, injectedAnom.Components);
  172. _stun.TryParalyze(ent, TimeSpan.FromSeconds(ent.Comp.StunDuration), true);
  173. if (ent.Comp.EndMessage is not null &&
  174. _mind.TryGetMind(ent, out _, out var mindComponent) &&
  175. mindComponent.Session != null)
  176. {
  177. var message = Loc.GetString(ent.Comp.EndMessage);
  178. var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
  179. _chat.ChatMessageToOne(ChatChannel.Server,
  180. message,
  181. wrappedMessage,
  182. default,
  183. false,
  184. mindComponent.Session.Channel,
  185. _messageColor);
  186. _popup.PopupEntity(message, ent, ent, PopupType.MediumCaution);
  187. _adminLog.Add(LogType.Anomaly, LogImpact.Medium,$"{ToPrettyString(ent)} is no longer a host for the anomaly.");
  188. }
  189. ent.Comp.Injected = false;
  190. RemCompDeferred<AnomalyComponent>(ent);
  191. }
  192. }