1
0

SharedShuttleSystem.cs 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. using Content.Shared.Containers.ItemSlots;
  2. using Content.Shared.Shuttles.BUIStates;
  3. using Content.Shared.Shuttles.Components;
  4. using Content.Shared.Shuttles.UI.MapObjects;
  5. using Content.Shared.Whitelist;
  6. using Robust.Shared.Map;
  7. using Robust.Shared.Map.Components;
  8. using Robust.Shared.Physics;
  9. using Robust.Shared.Physics.Collision.Shapes;
  10. using Robust.Shared.Physics.Components;
  11. namespace Content.Shared.Shuttles.Systems;
  12. public abstract partial class SharedShuttleSystem : EntitySystem
  13. {
  14. [Dependency] private readonly IMapManager _mapManager = default!;
  15. [Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
  16. [Dependency] protected readonly SharedMapSystem Maps = default!;
  17. [Dependency] protected readonly SharedTransformSystem XformSystem = default!;
  18. [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
  19. public const float FTLRange = 256f;
  20. public const float FTLBufferRange = 8f;
  21. private EntityQuery<MapGridComponent> _gridQuery;
  22. private EntityQuery<PhysicsComponent> _physicsQuery;
  23. private EntityQuery<TransformComponent> _xformQuery;
  24. private List<Entity<MapGridComponent>> _grids = new();
  25. public override void Initialize()
  26. {
  27. base.Initialize();
  28. _gridQuery = GetEntityQuery<MapGridComponent>();
  29. _physicsQuery = GetEntityQuery<PhysicsComponent>();
  30. _xformQuery = GetEntityQuery<TransformComponent>();
  31. }
  32. /// <summary>
  33. /// Returns whether an entity can FTL to the specified map.
  34. /// </summary>
  35. public bool CanFTLTo(EntityUid shuttleUid, MapId targetMap, EntityUid consoleUid)
  36. {
  37. var mapUid = _mapManager.GetMapEntityId(targetMap);
  38. var shuttleMap = _xformQuery.GetComponent(shuttleUid).MapID;
  39. if (shuttleMap == targetMap)
  40. return true;
  41. if (!TryComp<FTLDestinationComponent>(mapUid, out var destination) || !destination.Enabled)
  42. return false;
  43. if (destination.RequireCoordinateDisk)
  44. {
  45. if (!TryComp<ItemSlotsComponent>(consoleUid, out var slot))
  46. {
  47. return false;
  48. }
  49. if (!_itemSlots.TryGetSlot(consoleUid, SharedShuttleConsoleComponent.DiskSlotName, out var itemSlot, component: slot) || !itemSlot.HasItem)
  50. {
  51. return false;
  52. }
  53. if (itemSlot.Item is { Valid: true } disk)
  54. {
  55. ShuttleDestinationCoordinatesComponent? diskCoordinates = null;
  56. if (!Resolve(disk, ref diskCoordinates))
  57. {
  58. return false;
  59. }
  60. var diskCoords = diskCoordinates.Destination;
  61. if (diskCoords == null || !TryComp<FTLDestinationComponent>(diskCoords.Value, out var diskDestination) || diskDestination != destination)
  62. {
  63. return false;
  64. }
  65. }
  66. else
  67. {
  68. return false;
  69. }
  70. }
  71. if (HasComp<FTLMapComponent>(mapUid))
  72. return false;
  73. return _whitelistSystem.IsWhitelistPassOrNull(destination.Whitelist, shuttleUid);
  74. }
  75. /// <summary>
  76. /// Gets the list of map objects relevant for the specified map.
  77. /// </summary>
  78. public IEnumerable<(ShuttleExclusionObject Exclusion, MapCoordinates Coordinates)> GetExclusions(MapId mapId, List<ShuttleExclusionObject> exclusions)
  79. {
  80. foreach (var exc in exclusions)
  81. {
  82. var beaconCoords = XformSystem.ToMapCoordinates(GetCoordinates(exc.Coordinates));
  83. if (beaconCoords.MapId != mapId)
  84. continue;
  85. yield return (exc, beaconCoords);
  86. }
  87. }
  88. /// <summary>
  89. /// Gets the list of map objects relevant for the specified map.
  90. /// </summary>
  91. public IEnumerable<(ShuttleBeaconObject Beacon, MapCoordinates Coordinates)> GetBeacons(MapId mapId, List<ShuttleBeaconObject> beacons)
  92. {
  93. foreach (var beacon in beacons)
  94. {
  95. var beaconCoords = XformSystem.ToMapCoordinates(GetCoordinates(beacon.Coordinates));
  96. if (beaconCoords.MapId != mapId)
  97. continue;
  98. yield return (beacon, beaconCoords);
  99. }
  100. }
  101. public bool CanDraw(EntityUid gridUid, PhysicsComponent? physics = null, IFFComponent? iffComp = null)
  102. {
  103. if (!Resolve(gridUid, ref physics))
  104. return true;
  105. if (physics.BodyType != BodyType.Static && physics.Mass < 10f)
  106. {
  107. return false;
  108. }
  109. if (!Resolve(gridUid, ref iffComp, false))
  110. {
  111. return true;
  112. }
  113. // Hide it entirely.
  114. return (iffComp.Flags & IFFFlags.Hide) == 0x0;
  115. }
  116. public bool IsBeaconMap(EntityUid mapUid)
  117. {
  118. return TryComp(mapUid, out FTLDestinationComponent? ftlDest) && ftlDest.BeaconsOnly;
  119. }
  120. /// <summary>
  121. /// Returns true if a beacon can be FTLd to.
  122. /// </summary>
  123. public bool CanFTLBeacon(NetCoordinates nCoordinates)
  124. {
  125. // Only beacons parented to map supported.
  126. var coordinates = GetCoordinates(nCoordinates);
  127. return HasComp<MapComponent>(coordinates.EntityId);
  128. }
  129. public float GetFTLRange(EntityUid shuttleUid) => FTLRange;
  130. public float GetFTLBufferRange(EntityUid shuttleUid, MapGridComponent? grid = null)
  131. {
  132. if (!_gridQuery.Resolve(shuttleUid, ref grid))
  133. return 0f;
  134. var localAABB = grid.LocalAABB;
  135. var maxExtent = localAABB.MaxDimension / 2f;
  136. var range = maxExtent + FTLBufferRange;
  137. return range;
  138. }
  139. /// <summary>
  140. /// Returns true if the spot is free to be FTLd to (not close to any objects and in range).
  141. /// </summary>
  142. public bool FTLFree(EntityUid shuttleUid, EntityCoordinates coordinates, Angle angle, List<ShuttleExclusionObject>? exclusionZones)
  143. {
  144. if (!_physicsQuery.TryGetComponent(shuttleUid, out var shuttlePhysics) ||
  145. !_xformQuery.TryGetComponent(shuttleUid, out var shuttleXform))
  146. {
  147. return false;
  148. }
  149. // Just checks if any grids inside of a buffer range at the target position.
  150. _grids.Clear();
  151. var mapCoordinates = coordinates.ToMap(EntityManager, XformSystem);
  152. var ourPos = Maps.GetGridPosition((shuttleUid, shuttlePhysics, shuttleXform));
  153. // This is the already adjusted position
  154. var targetPosition = mapCoordinates.Position;
  155. // Check range even if it's cross-map.
  156. if ((targetPosition - ourPos).Length() > FTLRange)
  157. {
  158. return false;
  159. }
  160. // Check exclusion zones.
  161. // This needs to be passed in manually due to PVS.
  162. if (exclusionZones != null)
  163. {
  164. foreach (var exclusion in exclusionZones)
  165. {
  166. var exclusionCoords = XformSystem.ToMapCoordinates(GetCoordinates(exclusion.Coordinates));
  167. if (exclusionCoords.MapId != mapCoordinates.MapId)
  168. continue;
  169. if ((mapCoordinates.Position - exclusionCoords.Position).Length() <= exclusion.Range)
  170. return false;
  171. }
  172. }
  173. var ourFTLBuffer = GetFTLBufferRange(shuttleUid);
  174. var circle = new PhysShapeCircle(ourFTLBuffer + FTLBufferRange, targetPosition);
  175. _mapManager.FindGridsIntersecting(mapCoordinates.MapId, circle, Robust.Shared.Physics.Transform.Empty,
  176. ref _grids, includeMap: false);
  177. // If any grids in range that aren't us then can't FTL.
  178. foreach (var grid in _grids)
  179. {
  180. if (grid.Owner == shuttleUid)
  181. continue;
  182. return false;
  183. }
  184. return true;
  185. }
  186. }
  187. [Flags]
  188. public enum FTLState : byte
  189. {
  190. Invalid = 0,
  191. /// <summary>
  192. /// A dummy state for presentation
  193. /// </summary>
  194. Available = 1 << 0,
  195. /// <summary>
  196. /// Sound played and launch started
  197. /// </summary>
  198. Starting = 1 << 1,
  199. /// <summary>
  200. /// When they're on the FTL map
  201. /// </summary>
  202. Travelling = 1 << 2,
  203. /// <summary>
  204. /// Approaching destination, play effects or whatever,
  205. /// </summary>
  206. Arriving = 1 << 3,
  207. Cooldown = 1 << 4,
  208. }