// New Frontiers - This file is licensed under AGPLv3 // Copyright (c) 2024 New Frontiers Contributors // See AGPLv3.txt for details. using System.Numerics; using Content.Shared._NF.Shuttles.Events; using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Components; using Robust.Client.Graphics; using Robust.Shared.Collections; using Robust.Client.UserInterface; using Robust.Shared.Input; using Robust.Shared.Timing; using Content.Shared._Mono.Radar; using Content.Client._Mono.Radar; using Content.Client.Station; using Robust.Shared.Physics.Components; using Robust.Shared.Prototypes; namespace Content.Client.Shuttles.UI { public sealed partial class ShuttleNavControl { public bool HideTarget { get; set; } = false; public Vector2? Target { get; set; } = null; public NetEntity? TargetEntity { get; set; } = null; public InertiaDampeningMode DampeningMode { get; set; } public ServiceFlags ServiceFlags { get; set; } = ServiceFlags.None; private static readonly Color TargetColor = Color.FromHex("#9cae93ff"); /// /// Whether the shuttle is currently in FTL. This is used to disable the Park button /// while in FTL to prevent parking while traveling. /// public bool InFtl { get; set; } private void NfUpdateState(NavInterfaceState state) { if (state.MaxIffRange != null) MaximumIFFDistance = state.MaxIffRange.Value; HideCoords = state.HideCoords; Target = state.Target; TargetEntity = state.TargetEntity; HideTarget = state.HideTarget; if (!EntManager.GetCoordinates(state.Coordinates).HasValue || !EntManager.TryGetComponent(EntManager.GetCoordinates(state.Coordinates).GetValueOrDefault().EntityId, out TransformComponent? transform) || !EntManager.HasComponent(transform.GridUid)) { return; } DampeningMode = state.DampeningMode; Target = state.Target; TargetEntity = state.TargetEntity; // Check if the entity has an FTLComponent which indicates it's in FTL if (transform.GridUid != null) { InFtl = EntManager.HasComponent(transform.GridUid); } else { InFtl = false; } } // New Frontiers - Maximum IFF Distance - checks distance to object, draws if closer than max range // This code is licensed under AGPLv3. See AGPLv3.txt private bool NfCheckShouldDrawIffRangeCondition(bool shouldDrawIff, Vector2 distance) { if (shouldDrawIff && MaximumIFFDistance >= 0.0f) { if (distance.Length() > MaximumIFFDistance) { shouldDrawIff = false; } } return shouldDrawIff; } private static void NfAddBlipToList(List blipDataList, bool isOutsideRadarCircle, Vector2 uiPosition, int uiXCentre, int uiYCentre, Color color) { blipDataList.Add(new BlipData { IsOutsideRadarCircle = isOutsideRadarCircle, UiPosition = uiPosition, VectorToPosition = uiPosition - new Vector2(uiXCentre, uiYCentre), Color = color }); } private static void NfAddBlipToList(List blipDataList, bool isOutsideRadarCircle, Vector2 uiPosition, int uiXCentre, int uiYCentre, Color color, EntityUid gridUid = default) { Color blipColor = color; blipDataList.Add(new BlipData { IsOutsideRadarCircle = isOutsideRadarCircle, UiPosition = uiPosition, VectorToPosition = uiPosition - new Vector2(uiXCentre, uiYCentre), Color = blipColor }); } /** * Frontier - Adds blip style triangles that are on ships or pointing towards ships on the edges of the radar. * Draws blips at the BlipData's uiPosition and uses VectorToPosition to rotate to point towards ships. */ private void NfDrawBlips(DrawingHandleBase handle, List blipDataList) { var blipValueList = new Dictionary>(); foreach (var blipData in blipDataList) { var triangleShapeVectorPoints = new[] { new Vector2(0, 0), new Vector2(RadarBlipSize, 0), new Vector2(RadarBlipSize * 0.5f, RadarBlipSize) }; if (blipData.IsOutsideRadarCircle) { // Calculate the angle of rotation var angle = (float)Math.Atan2(blipData.VectorToPosition.Y, blipData.VectorToPosition.X) + -1.6f; // Manually create a rotation matrix var cos = (float)Math.Cos(angle); var sin = (float)Math.Sin(angle); float[,] rotationMatrix = { { cos, -sin }, { sin, cos } }; // Rotate each vertex for (var i = 0; i < triangleShapeVectorPoints.Length; i++) { var vertex = triangleShapeVectorPoints[i]; var x = vertex.X * rotationMatrix[0, 0] + vertex.Y * rotationMatrix[0, 1]; var y = vertex.X * rotationMatrix[1, 0] + vertex.Y * rotationMatrix[1, 1]; triangleShapeVectorPoints[i] = new Vector2(x, y); } } var triangleCenterVector = (triangleShapeVectorPoints[0] + triangleShapeVectorPoints[1] + triangleShapeVectorPoints[2]) / 3; // Calculate the vectors from the center to each vertex var vectorsFromCenter = new Vector2[3]; for (int i = 0; i < 3; i++) { vectorsFromCenter[i] = (triangleShapeVectorPoints[i] - triangleCenterVector) * UIScale; } // Calculate the vertices of the new triangle var newVerts = new Vector2[3]; for (var i = 0; i < 3; i++) { newVerts[i] = (blipData.UiPosition * UIScale) + vectorsFromCenter[i]; } if (!blipValueList.TryGetValue(blipData.Color, out var valueList)) { valueList = new ValueList(); } valueList.Add(newVerts[0]); valueList.Add(newVerts[1]); valueList.Add(newVerts[2]); blipValueList[blipData.Color] = valueList; } // One draw call for every color we have foreach (var color in blipValueList) { handle.DrawPrimitives(DrawPrimitiveTopology.TriangleList, color.Value.Span, color.Key); } } } }