From 6cdeb3d9cf63ff551eb91c356f3ab4bfe96bcac3 Mon Sep 17 00:00:00 2001 From: pathetic meowmeow Date: Thu, 25 Jun 2026 13:59:49 -0400 Subject: [PATCH] Suit sensors, but in space? Perish the thought. (#6054) --- .../CrewMonitoring/CrewMonitoringWindow.xaml | 5 +- .../CrewMonitoringWindow.xaml.cs | 26 ++- Content.Client/Pinpointer/UI/NavMapControl.cs | 11 +- .../CrewMonitoringShuttleControl.cs | 180 ++++++++++++++++++ .../SuitSensors/SharedSuitSensorSystem.cs | 7 +- .../Uniforms/base_clothinguniforms.yml | 4 +- .../Medical/handheld_crew_monitor.yml | 2 +- .../Machines/crew_monitor_server.yml | 2 +- .../Inventories/salvage_points.yml | 2 - .../Prototypes/_DV/Catalog/mining_voucher.yml | 1 - .../_DV/Entities/Objects/Misc/implanters.yml | 8 - .../Objects/Misc/subdermal_implants.yml | 15 -- 12 files changed, 226 insertions(+), 37 deletions(-) create mode 100644 Content.Client/_DV/CrewMonitoring/CrewMonitoringShuttleControl.cs diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml index 86e1ce689ac..aaf001a6a12 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml @@ -1,13 +1,16 @@ - + + + diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs index ad7fb5556dc..3553cef38dc 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs @@ -5,6 +5,7 @@ using Content.Client.Pinpointer.UI; using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; using Content.Shared.Medical.SuitSensor; +using Content.Shared.Station; // DeltaV - crew monitoring radar using Content.Shared.StatusIcon; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; @@ -27,6 +28,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private readonly SharedTransformSystem _transformSystem; private readonly SpriteSystem _spriteSystem; + private readonly SharedStationSystem _station; // DeltaV - crew monitoring radar private NetEntity? _trackedEntity; private bool _tryToScrollToListFocus; @@ -39,8 +41,10 @@ public sealed partial class CrewMonitoringWindow : FancyWindow _transformSystem = _entManager.System(); _spriteSystem = _entManager.System(); + _station = _entManager.System(); // DeltaV - crew monitoring radar NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; + ShuttleMap.NavMap = NavMap; // DeltaV - crew monitoring radar } public void Set(string stationName, EntityUid? mapUid) @@ -50,8 +54,10 @@ public sealed partial class CrewMonitoringWindow : FancyWindow if (_entManager.TryGetComponent(mapUid, out var xform)) NavMap.MapUid = xform.GridUid; - else - NavMap.Visible = false; + // Begin DeltaV - handle navmap visibility based on current position + // else + // NavMap.Visible = false; + // End DeltaV - handle navmap visibility based on current position StationName.AddStyleClass("LabelBig"); StationName.Text = stationName; @@ -62,6 +68,19 @@ public sealed partial class CrewMonitoringWindow : FancyWindow { base.FrameUpdate(args); + // Begin DeltaV - handle navmap visibility based on current position + if (_station.GetOwningStation(ShuttleMap.Owner) is not null) + { + NavMap.Visible = true; + ShuttleMap.Visible = false; + } + else + { + NavMap.Visible = false; + ShuttleMap.Visible = true; + } + // End DeltaV - handle navmap visibility based on current position + if (_tryToScrollToListFocus) TryToScrollToFocus(); } @@ -69,6 +88,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow public void ShowSensors(List sensors, EntityUid monitor, EntityCoordinates? monitorCoords) { ClearOutDatedData(); + ShuttleMap.Owner = monitor; // DeltaV - crew monitoring radar // No server label if (sensors.Count == 0) @@ -304,7 +324,7 @@ public sealed partial class CrewMonitoringWindow : FancyWindow jobContainer.AddChild(jobLabel); // Add user coordinates to the navmap - if (coordinates != null && NavMap.Visible && _blipTexture != null) + if (coordinates != null && _blipTexture != null) // DeltaV - don't filter the navmap visibility { NavMap.TrackedEntities.TryAdd(sensor.SuitSensorUid, new NavMapBlip diff --git a/Content.Client/Pinpointer/UI/NavMapControl.cs b/Content.Client/Pinpointer/UI/NavMapControl.cs index 47b5534d124..f9e363b5311 100644 --- a/Content.Client/Pinpointer/UI/NavMapControl.cs +++ b/Content.Client/Pinpointer/UI/NavMapControl.cs @@ -56,8 +56,8 @@ public partial class NavMapControl : MapGridControl // Constants protected float UpdateTime = 1.0f; - protected float MaxSelectableDistance = 10f; - protected float MinDragDistance = 5f; + public float MaxSelectableDistance = 10f; // DeltaV - accessible to CrewMonitoringShuttleControl + public float MinDragDistance = 5f; // DeltaV - accessible to CrewMonitoringShuttleControl protected static float MinDisplayedRange = 8f; protected static float MaxDisplayedRange = 128f; protected static float DefaultDisplayedRange = 48f; @@ -193,6 +193,13 @@ public partial class NavMapControl : MapGridControl _recenter.Disabled = false; } + // Begin DeltaV - we need access to that from outside + public void TrackEntity(NetEntity? entity) + { + TrackedEntitySelectedAction?.Invoke(entity); + } + // End DeltaV - we need access to that from outside + protected override void KeyBindUp(GUIBoundKeyEventArgs args) { base.KeyBindUp(args); diff --git a/Content.Client/_DV/CrewMonitoring/CrewMonitoringShuttleControl.cs b/Content.Client/_DV/CrewMonitoring/CrewMonitoringShuttleControl.cs new file mode 100644 index 00000000000..388a7bab8d2 --- /dev/null +++ b/Content.Client/_DV/CrewMonitoring/CrewMonitoringShuttleControl.cs @@ -0,0 +1,180 @@ +using System.Numerics; +using Content.Client.Pinpointer.UI; +using Content.Client.Shuttles.UI; +using Content.Shared.Shuttles.Components; +using Content.Shared.Shuttles.Systems; +using Robust.Client.Graphics; +using Robust.Client.UserInterface; +using Robust.Shared.Input; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; + +namespace Content.Client._DV.CrewMonitoring; + +public sealed class CrewMonitoringShuttleControl : BaseShuttleControl +{ + [Dependency] private readonly IMapManager _mapManager = default!; + private readonly SharedShuttleSystem _shuttles; + private readonly SharedTransformSystem _transform; + + public EntityUid? Owner; + public NavMapControl? NavMap; + + private List> _grids = new(); + + public CrewMonitoringShuttleControl() : base(64f, 256f, 256f) + { + _shuttles = EntManager.System(); + _transform = EntManager.System(); + } + + protected override void Draw(DrawingHandleScreen handle) + { + base.Draw(handle); + + DrawBacking(handle); + DrawCircles(handle); + + if (Owner is not { } owner || NavMap is not { } navMap) + return; + + var xformQuery = EntManager.GetEntityQuery(); + var fixturesQuery = EntManager.GetEntityQuery(); + var bodyQuery = EntManager.GetEntityQuery(); + var iffQuery = EntManager.GetEntityQuery(); + + if (!xformQuery.TryGetComponent(owner, out var xform) + || xform.MapID == MapId.Nullspace) + { + return; + } + + var coordinates = new EntityCoordinates(owner, Vector2.Zero); + + var mapPos = _transform.ToMapCoordinates(coordinates); + var ourEntRot = Angle.Zero; + var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot); + Matrix3x2.Invert(ourEntMatrix, out var worldToShuttle); + var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector); + var worldToView = worldToShuttle * shuttleToView; + + var viewBounds = new Box2Rotated(new Box2(-WorldRange, -WorldRange, WorldRange, WorldRange).Translated(mapPos.Position), ourEntRot, mapPos.Position); + var viewAABB = viewBounds.CalcBoundingBox(); + + _grids.Clear(); + _mapManager.FindGridsIntersecting(xform.MapID, new Box2(mapPos.Position - MaxRadarRangeVector, mapPos.Position + MaxRadarRangeVector), ref _grids, approx: true, includeMap: false); + + foreach (var grid in _grids) + { + if (!fixturesQuery.HasComponent(grid)) + continue; + + var body = bodyQuery.GetComponent(grid); + iffQuery.TryComp(grid, out var iff); + + if (!_shuttles.CanDraw(grid, body, iff)) + continue; + + var curGridToWorld = _transform.GetWorldMatrix(grid); + var curGridToView = curGridToWorld * worldToShuttle * shuttleToView; + + var gridAABB = curGridToWorld.TransformBox(grid.Comp.LocalAABB); + if (!gridAABB.Intersects(viewAABB)) + continue; + + var labelColor = _shuttles.GetIFFColor(grid, self: false, iff); + DrawGrid(handle, curGridToView, grid, labelColor); + } + + var curTime = Timing.RealTime; + var blinkFrequency = 1f / 1f; + var lit = curTime.TotalSeconds % blinkFrequency > blinkFrequency / 2f; + var box = SizeBox; + + foreach (var (coord, value) in navMap.TrackedCoordinates) + { + if (!lit || !value.Visible) + continue; + + var blipPos = _transform.ToMapCoordinates(coord); + + if (mapPos.MapId == MapId.Nullspace) + continue; + + handle.DrawCircle(Vector2.Clamp(Vector2.Transform(blipPos.Position, worldToView), box.TopLeft, box.BottomRight), float.Sqrt(MinimapScale) * 2f, value.Color); + } + + foreach (var blip in navMap.TrackedEntities.Values) + { + if (blip.Blinks && !lit) + continue; + + var blipPos = _transform.ToMapCoordinates(blip.Coordinates); + + if (mapPos.MapId == MapId.Nullspace) + continue; + + handle.DrawCircle(Vector2.Clamp(Vector2.Transform(blipPos.Position, worldToView), box.TopLeft, box.BottomRight), float.Sqrt(MinimapScale) * 2f, blip.Color); + } + } + + protected override void KeyBindUp(GUIBoundKeyEventArgs args) + { + base.KeyBindUp(args); + + if (Owner is not { } owner || NavMap is null) + return; + + if (!EntManager.TryGetComponent(owner, out var xform) || xform.MapID == MapId.Nullspace) + { + return; + } + + var ourEntRot = Angle.Zero; + var ourEntMatrix = Matrix3Helpers.CreateTransform(_transform.GetWorldPosition(xform), ourEntRot); + Matrix3x2.Invert(ourEntMatrix, out var worldToShuttle); + var shuttleToView = Matrix3x2.CreateScale(new Vector2(MinimapScale, -MinimapScale)) * Matrix3x2.CreateTranslation(MidPointVector); + var worldToView = worldToShuttle * shuttleToView; + Matrix3x2.Invert(worldToView, out var viewToWorld); + + if (args.Function == EngineKeyFunctions.UIClick) + { + if (NavMap.TrackedEntities.Count == 0) + return; + + if ((StartDragPosition - args.PointerLocation.Position).Length() > NavMap.MinDragDistance) + return; + + var localPosition = args.PointerLocation.Position - GlobalPixelPosition; + var worldPosition = Vector2.Transform(localPosition, viewToWorld); + + var closestEntity = NetEntity.Invalid; + var closestDistance = float.PositiveInfinity; + + foreach (var (currentEntity, blip) in NavMap.TrackedEntities) + { + if (!blip.Selectable) + continue; + + var currentDistance = (_transform.ToMapCoordinates(blip.Coordinates).Position - worldPosition).Length(); + + if (closestDistance < currentDistance || currentDistance * MinimapScale > NavMap.MaxSelectableDistance) + continue; + + closestEntity = currentEntity; + closestDistance = currentDistance; + } + + if (closestDistance > NavMap.MaxSelectableDistance || !closestEntity.IsValid()) + return; + + NavMap.TrackEntity(closestEntity); + } + else if (args.Function == EngineKeyFunctions.UIRightClick) + { + NavMap.TrackEntity(null); + } + } +} diff --git a/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs b/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs index 861fcd8dafe..3ce2cecfbae 100644 --- a/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs +++ b/Content.Shared/Medical/SuitSensors/SharedSuitSensorSystem.cs @@ -68,6 +68,11 @@ public abstract class SharedSuitSensorSystem : EntitySystem /// True if the sensor is assigned to a station or assigning it was successful. False otherwise. public bool CheckSensorAssignedStation(Entity sensor) { + // Begin DeltaV - fallback + if (sensor.Comp.StationId.HasValue && _stationSystem.GetOwningStation(sensor.Owner) is null) + return true; + // End DeltaV - fallback + if (!sensor.Comp.StationId.HasValue && Transform(sensor.Owner).GridUid == null) return false; @@ -348,7 +353,7 @@ public abstract class SharedSuitSensorSystem : EntitySystem var transform = ent.Comp2; // check if sensor is enabled and worn by user - if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null || !HasComp(sensor.User) || transform.GridUid == null) + if (sensor.Mode == SuitSensorMode.SensorOff || sensor.User == null || !HasComp(sensor.User)) // DeltaV - don't block on grids here return null; // try to get mobs id from ID slot diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml index ca9a1295ca6..5a7f0358cce 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/base_clothinguniforms.yml @@ -58,8 +58,8 @@ transmitFrequencyId: SuitSensor savableAddress: false - type: WirelessNetworkConnection - range: 1200 - - type: StationLimitedNetwork + range: 3600 # DeltaV - was 1200 + # - type: StationLimitedNetwork # DeltaV - this stinks and we don't want it to be limited - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml index 627bd6b3cd6..a9875c9fff1 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml @@ -23,7 +23,7 @@ receiveFrequencyId: NTNet # DeltaV - NTNet - type: WirelessNetworkConnection range: 500 - - type: StationLimitedNetwork + # - type: StationLimitedNetwork # DeltaV - don't restrict this unnecessarily - type: ReverseEngineering # Nyano difficulty: 2 recipes: diff --git a/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml b/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml index 7fa86226d6e..590bc2bc24f 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/crew_monitor_server.yml @@ -36,7 +36,7 @@ autoConnect: false - type: WirelessNetworkConnection range: 10000 # Delta-V Maximises the range for the Crew Monitor Server to make it work for Listening Post - - type: StationLimitedNetwork + # - type: StationLimitedNetwork # DeltaV - make this work for salvies - type: ApcPowerReceiver powerLoad: 200 - type: ExtensionCableReceiver diff --git a/Resources/Prototypes/_DV/Catalog/VendingMachines/Inventories/salvage_points.yml b/Resources/Prototypes/_DV/Catalog/VendingMachines/Inventories/salvage_points.yml index d5d57db6708..11075c1a0a1 100644 --- a/Resources/Prototypes/_DV/Catalog/VendingMachines/Inventories/salvage_points.yml +++ b/Resources/Prototypes/_DV/Catalog/VendingMachines/Inventories/salvage_points.yml @@ -61,5 +61,3 @@ - id: ShelterCapsuleBar cost: 10000 # TODO: mining drone stuff - - id: MedicalTrackingImplanter - cost: 10000 diff --git a/Resources/Prototypes/_DV/Catalog/mining_voucher.yml b/Resources/Prototypes/_DV/Catalog/mining_voucher.yml index 3c5359f3294..95d15b4f7b9 100644 --- a/Resources/Prototypes/_DV/Catalog/mining_voucher.yml +++ b/Resources/Prototypes/_DV/Catalog/mining_voucher.yml @@ -44,7 +44,6 @@ content: - ClothingBeltSalvageWebbing - ShelterCapsule - - MedicalTrackingImplanter - NFWeaponHoloflareGun # TODO: mining drone diff --git a/Resources/Prototypes/_DV/Entities/Objects/Misc/implanters.yml b/Resources/Prototypes/_DV/Entities/Objects/Misc/implanters.yml index fe16fa6e515..b286d20c55c 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Misc/implanters.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Misc/implanters.yml @@ -22,14 +22,6 @@ - type: Implanter implant: WatchdogImplant -- type: entity - parent: BaseImplantOnlyImplanter - id: MedicalTrackingImplanter - name: medical tracking implanter - components: - - type: Implanter - implant: MedicalTrackingImplant - - type: entity parent: BaseImplantOnlyImplanterCentcomm id: CentCommImplanter diff --git a/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml index 1df1c7c94f1..eb44e501ff9 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml @@ -41,21 +41,6 @@ targetUser: true radioChannel: Security -- type: entity - parent: BaseSubdermalImplant - id: MedicalTrackingImplant - categories: [ HideSpawnMenu ] - name: medical tracking implant - description: This implants transmits a message on the medical channel in case the user goes into critical state or dies. - components: - - type: TriggerOnMobstateChange - mobState: - - Critical - - Dead - - type: RattleOnTrigger - targetUser: true - radioChannel: Medical - - type: entity parent: BaseSubdermalImplant id: CentCommImplant