Add universal pinpointer (#13854)
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@ using Content.Shared.Pinpointer;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using Content.Server.Shuttles.Events;
|
using Content.Server.Shuttles.Events;
|
||||||
|
using Content.Shared.IdentityManagement;
|
||||||
|
|
||||||
namespace Content.Server.Pinpointer;
|
namespace Content.Server.Pinpointer;
|
||||||
|
|
||||||
@@ -18,12 +19,6 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
|
|||||||
SubscribeLocalEvent<FTLCompletedEvent>(OnLocateTarget);
|
SubscribeLocalEvent<FTLCompletedEvent>(OnLocateTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnActivate(EntityUid uid, PinpointerComponent component, ActivateInWorldEvent args)
|
|
||||||
{
|
|
||||||
TogglePinpointer(uid, component);
|
|
||||||
LocateTarget(uid, component);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TogglePinpointer(EntityUid uid, PinpointerComponent? pinpointer = null)
|
public bool TogglePinpointer(EntityUid uid, PinpointerComponent? pinpointer = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref pinpointer))
|
if (!Resolve(uid, ref pinpointer))
|
||||||
@@ -43,6 +38,14 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
|
|||||||
_appearance.SetData(uid, PinpointerVisuals.TargetDistance, pinpointer.DistanceToTarget, appearance);
|
_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)
|
private void OnLocateTarget(ref FTLCompletedEvent ev)
|
||||||
{
|
{
|
||||||
// This feels kind of expensive, but it only happens once per hyperspace jump
|
// 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
|
// todo: ideally, you would need to raise this event only on jumped entities
|
||||||
// this code update ALL pinpointers in game
|
// this code update ALL pinpointers in game
|
||||||
var query = EntityQueryEnumerator<PinpointerComponent>();
|
var query = EntityQueryEnumerator<PinpointerComponent>();
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out var pinpointer))
|
while (query.MoveNext(out var uid, out var pinpointer))
|
||||||
{
|
{
|
||||||
|
if (pinpointer.CanRetarget)
|
||||||
|
continue;
|
||||||
|
|
||||||
LocateTarget(uid, pinpointer);
|
LocateTarget(uid, pinpointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,7 +196,7 @@ public sealed class PinpointerSystem : SharedPinpointerSystem
|
|||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Distance CalculateDistance(Vector2 vec, PinpointerComponent pinpointer)
|
private Distance CalculateDistance(Vector2 vec, PinpointerComponent pinpointer)
|
||||||
{
|
{
|
||||||
var dist = vec.Length;
|
var dist = vec.Length;
|
||||||
if (dist <= pinpointer.ReachedDistance)
|
if (dist <= pinpointer.ReachedDistance)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Content.Shared.Pinpointer;
|
|||||||
public sealed partial class PinpointerComponent : Component
|
public sealed partial class PinpointerComponent : Component
|
||||||
{
|
{
|
||||||
// TODO: Type serializer oh god
|
// TODO: Type serializer oh god
|
||||||
[DataField("component")]
|
[DataField("component"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public string? Component;
|
public string? Component;
|
||||||
|
|
||||||
[DataField("mediumDistance"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("mediumDistance"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
@@ -30,19 +30,34 @@ public sealed partial class PinpointerComponent : Component
|
|||||||
[DataField("precision"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("precision"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public double Precision = 0.09;
|
public double Precision = 0.09;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name to display of the target being tracked.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("targetName"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public string? TargetName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the target name should be updated when the target is updated.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("updateTargetName"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool UpdateTargetName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not the target can be reassigned.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("canRetarget"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
public bool CanRetarget;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public EntityUid? Target = null;
|
public EntityUid? Target = null;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables, AutoNetworkedField]
|
||||||
[AutoNetworkedField]
|
|
||||||
public bool IsActive = false;
|
public bool IsActive = false;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables, AutoNetworkedField]
|
||||||
[AutoNetworkedField]
|
|
||||||
public Angle ArrowAngle;
|
public Angle ArrowAngle;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables, AutoNetworkedField]
|
||||||
[AutoNetworkedField]
|
|
||||||
public Distance DistanceToTarget = Distance.Unknown;
|
public Distance DistanceToTarget = Distance.Unknown;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
|
|||||||
@@ -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;
|
namespace Content.Shared.Pinpointer;
|
||||||
|
|
||||||
public abstract class SharedPinpointerSystem : EntitySystem
|
public abstract class SharedPinpointerSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<PinpointerComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
|
SubscribeLocalEvent<PinpointerComponent, AfterInteractEvent>(OnAfterInteract);
|
||||||
|
SubscribeLocalEvent<PinpointerComponent, ExaminedEvent>(OnExamined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the target if capable
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set pinpointers target to track
|
||||||
|
/// </summary>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update direction from pinpointer to selected target (if it was set)
|
||||||
|
/// </summary>
|
||||||
|
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)));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Manually set distance from pinpointer to target
|
/// Manually set distance from pinpointer to target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -49,4 +119,25 @@ public abstract class SharedPinpointerSystem : EntitySystem
|
|||||||
pinpointer.IsActive = isActive;
|
pinpointer.IsActive = isActive;
|
||||||
Dirty(pinpointer);
|
Dirty(pinpointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggle Pinpointer screen. If it has target it will start tracking it.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>True if pinpointer was activated, false otherwise</returns>
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
Resources/Locale/en-US/pinpointer/pinpointer.ftl
Normal file
1
Resources/Locale/en-US/pinpointer/pinpointer.ftl
Normal file
@@ -0,0 +1 @@
|
|||||||
|
examine-pinpointer-linked = It is tracking: {$target}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
name: pinpointer
|
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
|
parent: BaseItem
|
||||||
id: PinpointerBase
|
id: PinpointerBase
|
||||||
abstract: true
|
abstract: true
|
||||||
@@ -43,3 +43,14 @@
|
|||||||
components:
|
components:
|
||||||
- type: Pinpointer
|
- type: Pinpointer
|
||||||
component: NukeDisk
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user