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 partial class SharedPinpointerSystem : EntitySystem { [Dependency] private ISharedAdminLogManager _adminLogger = default!; [Dependency] private EmagSystem _emag = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnEmagged); SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnExamined); } /// /// Set the target if capable /// private void OnAfterInteract(Entity ent, ref AfterInteractEvent args) { if (!args.CanReach || args.Target is not { } target) return; if (!ent.Comp.CanRetarget || ent.Comp.IsActive) return; // TODO add doafter once the freeze is lifted args.Handled = true; ent.Comp.Target = args.Target; _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(args.User):player} set target of {ToPrettyString(ent):pinpointer} to {ToPrettyString(ent.Comp.Target.Value):target}"); if (ent.Comp.UpdateTargetName) ent.Comp.TargetName = ent.Comp.Target == null ? null : Identity.Name(ent.Comp.Target.Value, EntityManager); } /// /// Set pinpointers target to track /// public virtual void SetTarget(Entity ent, EntityUid? target) { if (!Resolve(ent, ref ent.Comp)) return; var pinpointer = ent.Comp; 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(ent); } /// /// Update direction from pinpointer to selected target (if it was set) /// protected virtual void UpdateDirectionToTarget(Entity ent) { } private void OnExamined(Entity ent, ref ExaminedEvent args) { if (!args.IsInDetailsRange || ent.Comp.TargetName == null) return; args.PushMarkup(Loc.GetString("examine-pinpointer-linked", ("target", ent.Comp.TargetName))); } /// /// Manually set distance from pinpointer to target /// public void SetDistance(Entity ent, Distance distance) { if (!Resolve(ent, ref ent.Comp)) return; if (distance == ent.Comp.DistanceToTarget) return; ent.Comp.DistanceToTarget = distance; Dirty(ent); } /// /// Try to manually set pinpointer arrow direction. /// If difference between current angle and new angle is smaller than /// pinpointer precision, new value will be ignored and it will return false. /// public bool TrySetArrowAngle(Entity ent, Angle arrowAngle) { if (!Resolve(ent, ref ent.Comp)) return false; if (ent.Comp.ArrowAngle.EqualsApprox(arrowAngle, ent.Comp.Precision)) return false; ent.Comp.ArrowAngle = arrowAngle; Dirty(ent); return true; } /// /// Activate/deactivate pinpointer screen. If it has target it will start tracking it. /// public void SetActive(Entity ent, bool isActive) { if (!Resolve(ent, ref ent.Comp)) return; if (isActive == ent.Comp.IsActive) return; ent.Comp.IsActive = isActive; Dirty(ent); } /// /// Toggle Pinpointer screen. If it has target it will start tracking it. /// /// True if pinpointer was activated, false otherwise public virtual bool TogglePinpointer(Entity ent) { if (!Resolve(ent, ref ent.Comp)) return false; var isActive = !ent.Comp.IsActive; SetActive(ent, isActive); return isActive; } private void OnEmagged(Entity ent, ref GotEmaggedEvent args) { if (!_emag.CompareFlag(args.Type, EmagType.Interaction)) return; if (_emag.CheckFlag(ent, EmagType.Interaction)) return; if (ent.Comp.CanRetarget) return; args.Handled = true; ent.Comp.CanRetarget = true; } }