1
0

ParticleAcceleratorSystem.Parts.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using System.Diagnostics.CodeAnalysis;
  2. using Content.Server.ParticleAccelerator.Components;
  3. using JetBrains.Annotations;
  4. using Robust.Shared.Map.Components;
  5. using Robust.Shared.Physics.Events;
  6. namespace Content.Server.ParticleAccelerator.EntitySystems;
  7. [UsedImplicitly]
  8. public sealed partial class ParticleAcceleratorSystem
  9. {
  10. private void InitializePartSystem()
  11. {
  12. SubscribeLocalEvent<ParticleAcceleratorPartComponent, ComponentShutdown>(OnComponentShutdown);
  13. SubscribeLocalEvent<ParticleAcceleratorPartComponent, MoveEvent>(OnMoveEvent);
  14. SubscribeLocalEvent<ParticleAcceleratorPartComponent, PhysicsBodyTypeChangedEvent>(BodyTypeChanged);
  15. }
  16. public void RescanParts(EntityUid uid, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? controller = null)
  17. {
  18. if (!Resolve(uid, ref controller))
  19. return;
  20. if (controller.CurrentlyRescanning)
  21. return;
  22. var partQuery = GetEntityQuery<ParticleAcceleratorPartComponent>();
  23. foreach (var part in AllParts(uid, controller))
  24. {
  25. if (partQuery.TryGetComponent(part, out var partState))
  26. partState.Master = null;
  27. }
  28. controller.Assembled = false;
  29. controller.FuelChamber = null;
  30. controller.EndCap = null;
  31. controller.PowerBox = null;
  32. controller.PortEmitter = null;
  33. controller.ForeEmitter = null;
  34. controller.StarboardEmitter = null;
  35. var xformQuery = GetEntityQuery<TransformComponent>();
  36. if (!xformQuery.TryGetComponent(uid, out var xform) || !xform.Anchored)
  37. {
  38. SwitchOff(uid, user, controller);
  39. return;
  40. }
  41. var gridUid = xform.GridUid;
  42. if (gridUid == null || gridUid != xform.ParentUid || !TryComp<MapGridComponent>(gridUid, out var grid))
  43. {
  44. SwitchOff(uid, user, controller);
  45. return;
  46. }
  47. // Find fuel chamber first by scanning cardinals.
  48. var fuelQuery = GetEntityQuery<ParticleAcceleratorFuelChamberComponent>();
  49. foreach (var adjacent in _mapSystem.GetCardinalNeighborCells(gridUid.Value, grid, xform.Coordinates))
  50. {
  51. if (fuelQuery.HasComponent(adjacent)
  52. && partQuery.TryGetComponent(adjacent, out var partState)
  53. && partState.Master == null)
  54. {
  55. controller.FuelChamber = adjacent;
  56. break;
  57. }
  58. }
  59. if (controller.FuelChamber == null)
  60. {
  61. SwitchOff(uid, user, controller);
  62. return;
  63. }
  64. // When we call SetLocalRotation down there to rotate the control box,
  65. // that ends up re-entrantly calling RescanParts() through the move event.
  66. // You'll have to take my word for it that that breaks everything, yeah?
  67. controller.CurrentlyRescanning = true;
  68. // Automatically rotate the control box sprite to face the fuel chamber
  69. var fuelXform = xformQuery.GetComponent(controller.FuelChamber!.Value);
  70. var fuelDir = (fuelXform.LocalPosition - xform.LocalPosition).GetDir();
  71. _transformSystem.SetLocalRotation(uid, fuelDir.ToAngle(), xform);
  72. // Calculate offsets for each of the parts of the PA.
  73. // These are all done relative to the fuel chamber BC that is basically the center of the machine.
  74. var rotation = fuelXform.LocalRotation;
  75. var offsetVect = rotation.GetCardinalDir().ToIntVec();
  76. var orthoOffsetVect = new Vector2i(-offsetVect.Y, offsetVect.X);
  77. var positionFuelChamber = _mapSystem.TileIndicesFor(gridUid!.Value, grid, fuelXform.Coordinates); // n // n: End Cap
  78. var positionEndCap = positionFuelChamber - offsetVect; // CF // C: Control Box, F: Fuel Chamber
  79. var positionPowerBox = positionFuelChamber + offsetVect; // P // P: Power Box
  80. var positionPortEmitter = positionFuelChamber + offsetVect * 2 + orthoOffsetVect; // EEE // E: Emitter (Starboard, Fore, Port)
  81. var positionForeEmitter = positionFuelChamber + offsetVect * 2;
  82. var positionStarboardEmitter = positionFuelChamber + offsetVect * 2 - orthoOffsetVect;
  83. ScanPart<ParticleAcceleratorEndCapComponent>(gridUid.Value, positionEndCap, rotation, out controller.EndCap, out _, grid);
  84. ScanPart<ParticleAcceleratorPowerBoxComponent>(gridUid.Value, positionPowerBox, rotation, out controller.PowerBox, out _, grid);
  85. if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid.Value, positionPortEmitter, rotation, out controller.PortEmitter, out var portEmitter, grid)
  86. || portEmitter.Type != ParticleAcceleratorEmitterType.Port)
  87. controller.PortEmitter = null;
  88. if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid.Value, positionForeEmitter, rotation, out controller.ForeEmitter, out var foreEmitter, grid)
  89. || foreEmitter.Type != ParticleAcceleratorEmitterType.Fore)
  90. controller.ForeEmitter = null;
  91. if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid.Value, positionStarboardEmitter, rotation, out controller.StarboardEmitter, out var starboardEmitter, grid)
  92. || starboardEmitter.Type != ParticleAcceleratorEmitterType.Starboard)
  93. controller.StarboardEmitter = null;
  94. controller.Assembled =
  95. controller.FuelChamber.HasValue
  96. && controller.EndCap.HasValue
  97. && controller.PowerBox.HasValue
  98. && controller.PortEmitter.HasValue
  99. && controller.ForeEmitter.HasValue
  100. && controller.StarboardEmitter.HasValue;
  101. foreach (var part in AllParts(uid, controller))
  102. {
  103. if (partQuery.TryGetComponent(part, out var partState))
  104. partState.Master = uid;
  105. }
  106. controller.CurrentlyRescanning = false;
  107. UpdatePowerDraw(uid, controller);
  108. UpdateUI(uid, controller);
  109. }
  110. private bool ScanPart<T>(EntityUid uid, Vector2i coordinates, Angle? rotation, [NotNullWhen(true)] out EntityUid? part, [NotNullWhen(true)] out T? comp, MapGridComponent? grid = null)
  111. where T : IComponent
  112. {
  113. if (!Resolve(uid, ref grid))
  114. {
  115. part = null;
  116. comp = default;
  117. return false;
  118. }
  119. var compQuery = GetEntityQuery<T>();
  120. foreach (var entity in _mapSystem.GetAnchoredEntities(uid, grid, coordinates))
  121. {
  122. if (compQuery.TryGetComponent(entity, out comp)
  123. && TryComp<ParticleAcceleratorPartComponent>(entity, out var partState) && partState.Master == null
  124. && (rotation == null || Transform(entity).LocalRotation.EqualsApprox(rotation!.Value.Theta)))
  125. {
  126. part = entity;
  127. return true;
  128. }
  129. }
  130. part = null;
  131. comp = default;
  132. return false;
  133. }
  134. private void OnComponentShutdown(EntityUid uid, ParticleAcceleratorPartComponent comp, ComponentShutdown args)
  135. {
  136. if (Exists(comp.Master))
  137. RescanParts(comp.Master!.Value);
  138. }
  139. private void BodyTypeChanged(EntityUid uid, ParticleAcceleratorPartComponent comp, ref PhysicsBodyTypeChangedEvent args)
  140. {
  141. if (Exists(comp.Master))
  142. RescanParts(comp.Master!.Value);
  143. }
  144. private void OnMoveEvent(EntityUid uid, ParticleAcceleratorPartComponent comp, ref MoveEvent args)
  145. {
  146. if (Exists(comp.Master))
  147. RescanParts(comp.Master!.Value);
  148. }
  149. }