From 57cd8006f9af3d7ebf54a8bee32e4e469443c1a2 Mon Sep 17 00:00:00 2001 From: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com> Date: Sun, 28 May 2023 05:24:09 -0500 Subject: [PATCH] Add universal pinpointer (#13854) Co-authored-by: metalgearsloth --- Content.Server/Pinpointer/PinpointerSystem.cs | 21 +++-- .../Pinpointer/PinpointerComponent.cs | 29 ++++-- .../Pinpointer/SharedPinpointerSystem.cs | 91 +++++++++++++++++++ .../Locale/en-US/pinpointer/pinpointer.ftl | 1 + .../Entities/Objects/Devices/pinpointer.yml | 13 ++- 5 files changed, 140 insertions(+), 15 deletions(-) create mode 100644 Resources/Locale/en-US/pinpointer/pinpointer.ftl diff --git a/Content.Server/Pinpointer/PinpointerSystem.cs b/Content.Server/Pinpointer/PinpointerSystem.cs index e0b5af3192..d0e4831891 100644 --- a/Content.Server/Pinpointer/PinpointerSystem.cs +++ b/Content.Server/Pinpointer/PinpointerSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Pinpointer; using System.Linq; using Robust.Shared.Utility; using Content.Server.Shuttles.Events; +using Content.Shared.IdentityManagement; namespace Content.Server.Pinpointer; @@ -18,12 +19,6 @@ public sealed class PinpointerSystem : SharedPinpointerSystem SubscribeLocalEvent(OnLocateTarget); } - private void OnActivate(EntityUid uid, PinpointerComponent component, ActivateInWorldEvent args) - { - TogglePinpointer(uid, component); - LocateTarget(uid, component); - } - public bool TogglePinpointer(EntityUid uid, PinpointerComponent? pinpointer = null) { if (!Resolve(uid, ref pinpointer)) @@ -43,6 +38,14 @@ public sealed class PinpointerSystem : SharedPinpointerSystem _appearance.SetData(uid, PinpointerVisuals.TargetDistance, pinpointer.DistanceToTarget, appearance); } + private void OnActivate(EntityUid uid, PinpointerComponent component, ActivateInWorldEvent args) + { + TogglePinpointer(uid, component); + + if (!component.CanRetarget) + LocateTarget(uid, component); + } + private void OnLocateTarget(ref FTLCompletedEvent ev) { // This feels kind of expensive, but it only happens once per hyperspace jump @@ -50,8 +53,12 @@ public sealed class PinpointerSystem : SharedPinpointerSystem // todo: ideally, you would need to raise this event only on jumped entities // this code update ALL pinpointers in game var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var pinpointer)) { + if (pinpointer.CanRetarget) + continue; + LocateTarget(uid, pinpointer); } } @@ -189,7 +196,7 @@ public sealed class PinpointerSystem : SharedPinpointerSystem return dir; } - private static Distance CalculateDistance(Vector2 vec, PinpointerComponent pinpointer) + private Distance CalculateDistance(Vector2 vec, PinpointerComponent pinpointer) { var dist = vec.Length; if (dist <= pinpointer.ReachedDistance) diff --git a/Content.Shared/Pinpointer/PinpointerComponent.cs b/Content.Shared/Pinpointer/PinpointerComponent.cs index 0b49ad5e99..e83a2e38d6 100644 --- a/Content.Shared/Pinpointer/PinpointerComponent.cs +++ b/Content.Shared/Pinpointer/PinpointerComponent.cs @@ -12,7 +12,7 @@ namespace Content.Shared.Pinpointer; public sealed partial class PinpointerComponent : Component { // TODO: Type serializer oh god - [DataField("component")] + [DataField("component"), ViewVariables(VVAccess.ReadWrite)] public string? Component; [DataField("mediumDistance"), ViewVariables(VVAccess.ReadWrite)] @@ -30,19 +30,34 @@ public sealed partial class PinpointerComponent : Component [DataField("precision"), ViewVariables(VVAccess.ReadWrite)] public double Precision = 0.09; + /// + /// Name to display of the target being tracked. + /// + [DataField("targetName"), ViewVariables(VVAccess.ReadWrite)] + public string? TargetName; + + /// + /// Whether or not the target name should be updated when the target is updated. + /// + [DataField("updateTargetName"), ViewVariables(VVAccess.ReadWrite)] + public bool UpdateTargetName; + + /// + /// Whether or not the target can be reassigned. + /// + [DataField("canRetarget"), ViewVariables(VVAccess.ReadWrite)] + public bool CanRetarget; + [ViewVariables] public EntityUid? Target = null; - [ViewVariables] - [AutoNetworkedField] + [ViewVariables, AutoNetworkedField] public bool IsActive = false; - [ViewVariables] - [AutoNetworkedField] + [ViewVariables, AutoNetworkedField] public Angle ArrowAngle; - [ViewVariables] - [AutoNetworkedField] + [ViewVariables, AutoNetworkedField] public Distance DistanceToTarget = Distance.Unknown; [ViewVariables] diff --git a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs index 5491e53dd2..43550f2919 100644 --- a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs +++ b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs @@ -1,7 +1,77 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.Emag.Systems; +using Content.Shared.Examine; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; + namespace Content.Shared.Pinpointer; public abstract class SharedPinpointerSystem : EntitySystem { + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnEmagged); + SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnExamined); + } + + /// + /// Set the target if capable + /// + private void OnAfterInteract(EntityUid uid, PinpointerComponent component, AfterInteractEvent args) + { + if (!args.CanReach || args.Target is not { } target) + return; + + if (!component.CanRetarget || component.IsActive) + return; + + // TODO add doafter once the freeze is lifted + args.Handled = true; + component.Target = args.Target; + _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.User):player} set target of {ToPrettyString(uid):pinpointer} to {ToPrettyString(component.Target.Value):target}"); + if (component.UpdateTargetName) + component.TargetName = component.Target == null ? null : Identity.Name(component.Target.Value, EntityManager); + } + + /// + /// Set pinpointers target to track + /// + public void SetTarget(EntityUid uid, EntityUid? target, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return; + + if (pinpointer.Target == target) + return; + + pinpointer.Target = target; + if (pinpointer.UpdateTargetName) + pinpointer.TargetName = target == null ? null : Identity.Name(target.Value, EntityManager); + if (pinpointer.IsActive) + UpdateDirectionToTarget(uid, pinpointer); + } + + /// + /// Update direction from pinpointer to selected target (if it was set) + /// + protected virtual void UpdateDirectionToTarget(EntityUid uid, PinpointerComponent? pinpointer = null) + { + + } + + private void OnExamined(EntityUid uid, PinpointerComponent component, ExaminedEvent args) + { + if (!args.IsInDetailsRange || component.TargetName == null) + return; + + args.PushMarkup(Loc.GetString("examine-pinpointer-linked", ("target", component.TargetName))); + } + /// /// Manually set distance from pinpointer to target /// @@ -49,4 +119,25 @@ public abstract class SharedPinpointerSystem : EntitySystem pinpointer.IsActive = isActive; Dirty(pinpointer); } + + + /// + /// Toggle Pinpointer screen. If it has target it will start tracking it. + /// + /// True if pinpointer was activated, false otherwise + public bool TogglePinpointer(EntityUid uid, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return false; + + var isActive = !pinpointer.IsActive; + SetActive(uid, isActive, pinpointer); + return isActive; + } + + private void OnEmagged(EntityUid uid, PinpointerComponent component, ref GotEmaggedEvent args) + { + args.Handled = true; + component.CanRetarget = true; + } } diff --git a/Resources/Locale/en-US/pinpointer/pinpointer.ftl b/Resources/Locale/en-US/pinpointer/pinpointer.ftl new file mode 100644 index 0000000000..d19ba84f03 --- /dev/null +++ b/Resources/Locale/en-US/pinpointer/pinpointer.ftl @@ -0,0 +1 @@ +examine-pinpointer-linked = It is tracking: {$target} diff --git a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml index 054bb26ea6..2490c3a3d6 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml @@ -1,6 +1,6 @@ - type: entity name: pinpointer - description: A handheld tracking device that locks onto certain signals. + description: A handheld tracking device. While typically far more capable, this one has been configured to lock onto certain signals. parent: BaseItem id: PinpointerBase abstract: true @@ -43,3 +43,14 @@ components: - type: Pinpointer component: NukeDisk + targetName: nuclear authentication disk + +- type: entity + name: universal pinpointer + description: A handheld tracking device that locks onto any physical entity while off. + id: PinpointerUniversal + parent: PinpointerBase + components: + - type: Pinpointer + updateTargetName: true + canRetarget: true