ArtifactCrusherSystem.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. using Content.Server.Body.Systems;
  2. using Content.Server.Popups;
  3. using Content.Server.Power.Components;
  4. using Content.Server.Power.EntitySystems;
  5. using Content.Server.Stack;
  6. using Content.Server.Storage.Components;
  7. using Content.Server.Xenoarchaeology.XenoArtifacts;
  8. using Content.Shared.Body.Components;
  9. using Content.Shared.Damage;
  10. using Content.Shared.Power;
  11. using Content.Shared.Verbs;
  12. using Content.Shared.Whitelist;
  13. using Content.Shared.Xenoarchaeology.Equipment;
  14. using Robust.Shared.Collections;
  15. using Robust.Shared.Random;
  16. using Robust.Shared.Timing;
  17. namespace Content.Server.Xenoarchaeology.Equipment.Systems;
  18. /// <inheritdoc/>
  19. public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
  20. {
  21. [Dependency] private readonly IGameTiming _timing = default!;
  22. [Dependency] private readonly IRobustRandom _random = default!;
  23. [Dependency] private readonly ArtifactSystem _artifact = default!;
  24. [Dependency] private readonly BodySystem _body = default!;
  25. [Dependency] private readonly DamageableSystem _damageable = default!;
  26. [Dependency] private readonly StackSystem _stack = default!;
  27. [Dependency] private readonly PopupSystem _popup = default!;
  28. [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
  29. /// <inheritdoc/>
  30. public override void Initialize()
  31. {
  32. base.Initialize();
  33. SubscribeLocalEvent<ArtifactCrusherComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
  34. SubscribeLocalEvent<ArtifactCrusherComponent, PowerChangedEvent>(OnPowerChanged);
  35. }
  36. private void OnGetVerbs(Entity<ArtifactCrusherComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
  37. {
  38. if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing)
  39. return;
  40. if (!TryComp<EntityStorageComponent>(ent, out var entityStorageComp) ||
  41. entityStorageComp.Contents.ContainedEntities.Count == 0)
  42. return;
  43. if (!this.IsPowered(ent, EntityManager))
  44. return;
  45. var verb = new AlternativeVerb
  46. {
  47. Text = Loc.GetString("artifact-crusher-verb-start-crushing"),
  48. Priority = 2,
  49. Act = () => StartCrushing((ent, ent.Comp, entityStorageComp))
  50. };
  51. args.Verbs.Add(verb);
  52. }
  53. private void OnPowerChanged(Entity<ArtifactCrusherComponent> ent, ref PowerChangedEvent args)
  54. {
  55. if (!args.Powered)
  56. StopCrushing(ent);
  57. }
  58. public void StartCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
  59. {
  60. var (uid, crusher, _) = ent;
  61. if (crusher.Crushing)
  62. return;
  63. if (crusher.AutoLock)
  64. _popup.PopupEntity(Loc.GetString("artifact-crusher-autolocks-enable"), uid);
  65. crusher.Crushing = true;
  66. crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
  67. crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration;
  68. crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent);
  69. Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true);
  70. Dirty(ent, ent.Comp1);
  71. }
  72. public void FinishCrushing(Entity<ArtifactCrusherComponent, EntityStorageComponent> ent)
  73. {
  74. var (_, crusher, storage) = ent;
  75. StopCrushing((ent, ent.Comp1), false);
  76. AudioSystem.PlayPvs(crusher.CrushingCompleteSound, ent);
  77. crusher.CrushingSoundEntity = null;
  78. Dirty(ent, ent.Comp1);
  79. var contents = new ValueList<EntityUid>(storage.Contents.ContainedEntities);
  80. var coords = Transform(ent).Coordinates;
  81. foreach (var contained in contents)
  82. {
  83. if (_whitelistSystem.IsWhitelistPass(crusher.CrushingWhitelist, contained))
  84. {
  85. var amount = _random.Next(crusher.MinFragments, crusher.MaxFragments);
  86. var stacks = _stack.SpawnMultiple(crusher.FragmentStackProtoId, amount, coords);
  87. foreach (var stack in stacks)
  88. {
  89. ContainerSystem.Insert((stack, null, null, null), crusher.OutputContainer);
  90. }
  91. _artifact.ForceActivateArtifact(contained);
  92. }
  93. if (!TryComp<BodyComponent>(contained, out var body))
  94. Del(contained);
  95. var gibs = _body.GibBody(contained, body: body, gibOrgans: true);
  96. foreach (var gib in gibs)
  97. {
  98. ContainerSystem.Insert((gib, null, null, null), crusher.OutputContainer);
  99. }
  100. }
  101. }
  102. public override void Update(float frameTime)
  103. {
  104. base.Update(frameTime);
  105. var query = EntityQueryEnumerator<ArtifactCrusherComponent, EntityStorageComponent>();
  106. while (query.MoveNext(out var uid, out var crusher, out var storage))
  107. {
  108. if (!crusher.Crushing)
  109. continue;
  110. if (crusher.NextSecond < _timing.CurTime)
  111. {
  112. var contents = new ValueList<EntityUid>(storage.Contents.ContainedEntities);
  113. foreach (var contained in contents)
  114. {
  115. _damageable.TryChangeDamage(contained, crusher.CrushingDamage);
  116. }
  117. crusher.NextSecond += TimeSpan.FromSeconds(1);
  118. Dirty(uid, crusher);
  119. }
  120. if (crusher.CrushEndTime < _timing.CurTime)
  121. {
  122. FinishCrushing((uid, crusher, storage));
  123. }
  124. }
  125. }
  126. }