From c1cf22d97ed31b765a767cdd5df0b996cf150c15 Mon Sep 17 00:00:00 2001 From: Alex Evgrashin Date: Thu, 4 Nov 2021 00:35:34 +0300 Subject: [PATCH] Pinpointer (#5131) * Add pinpointer sprites * Start working on pinpointer * Updated pinpointer * Working on visuals * Working on a pinpointer and eye rotation * Add client/server pinpointers systems * Minor cleanup * Add distance support * Add nuke tag * Remove redundant flag and add pinpointer to caps locker * Disable rotation of pinpointer * Fixed distance Co-authored-by: Alexander Evgrashin --- .../Pinpointer/ClientPinpointerSystem.cs | 88 ++++++++++ .../Pinpointer/PinpointerVisualizer.cs | 60 +++++++ .../Pinpointer/ServerPinpointerSystem.cs | 158 +++++++++++++++++ .../Pinpointer/PinpointerComponent.cs | 54 ++++++ .../Pinpointer/PinpointerVisuals.cs | 19 ++ .../Pinpointer/SharedPinpointerSystem.cs | 93 ++++++++++ .../Catalog/Fills/Lockers/heads.yml | 2 + .../Entities/Objects/Devices/pinpointer.yml | 33 ++++ .../Entities/Objects/Misc/dat_fukken_disk.yml | 16 +- Resources/Prototypes/tags.yml | 2 + .../Devices/pinpointer.rsi/inhand-left.png | Bin 0 -> 196 bytes .../Devices/pinpointer.rsi/inhand-right.png | Bin 0 -> 198 bytes .../Objects/Devices/pinpointer.rsi/meta.json | 162 ++++++++++++++++++ .../Devices/pinpointer.rsi/pinonalert.png | Bin 0 -> 577 bytes .../pinpointer.rsi/pinonalertdirect.png | Bin 0 -> 196 bytes .../Devices/pinpointer.rsi/pinonalertnull.png | Bin 0 -> 212 bytes .../Devices/pinpointer.rsi/pinonclose.png | Bin 0 -> 4979 bytes .../Devices/pinpointer.rsi/pinondirect.png | Bin 0 -> 166 bytes .../pinpointer.rsi/pinondirectlarge.png | Bin 0 -> 173 bytes .../pinpointer.rsi/pinondirectsmall.png | Bin 0 -> 152 bytes .../pinpointer.rsi/pinondirectxtrlarge.png | Bin 0 -> 159 bytes .../Devices/pinpointer.rsi/pinonfar.png | Bin 0 -> 230 bytes .../Devices/pinpointer.rsi/pinonmedium.png | Bin 0 -> 4978 bytes .../Devices/pinpointer.rsi/pinonnull.png | Bin 0 -> 182 bytes .../Devices/pinpointer.rsi/pinpointer.png | Bin 0 -> 276 bytes .../pinpointer.rsi/pinpointer_crew.png | Bin 0 -> 265 bytes .../pinpointer.rsi/pinpointer_crewprox.png | Bin 0 -> 315 bytes .../pinpointer.rsi/pinpointer_syndicate.png | Bin 0 -> 237 bytes .../Devices/pinpointer.rsi/pinpointer_way.png | Bin 0 -> 266 bytes 29 files changed, 686 insertions(+), 1 deletion(-) create mode 100644 Content.Client/Pinpointer/ClientPinpointerSystem.cs create mode 100644 Content.Client/Pinpointer/PinpointerVisualizer.cs create mode 100644 Content.Server/Pinpointer/ServerPinpointerSystem.cs create mode 100644 Content.Shared/Pinpointer/PinpointerComponent.cs create mode 100644 Content.Shared/Pinpointer/PinpointerVisuals.cs create mode 100644 Content.Shared/Pinpointer/SharedPinpointerSystem.cs create mode 100644 Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinonalert.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinonalertdirect.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinonalertnull.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinonclose.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirect.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectlarge.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectsmall.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectxtrlarge.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinonfar.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinonmedium.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinonnull.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_crew.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_crewprox.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_syndicate.png create mode 100644 Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_way.png diff --git a/Content.Client/Pinpointer/ClientPinpointerSystem.cs b/Content.Client/Pinpointer/ClientPinpointerSystem.cs new file mode 100644 index 0000000000..646247959d --- /dev/null +++ b/Content.Client/Pinpointer/ClientPinpointerSystem.cs @@ -0,0 +1,88 @@ +using Content.Shared.Pinpointer; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.IoC; +using Robust.Shared.Maths; + +namespace Content.Client.Pinpointer +{ + public sealed class ClientPinpointerSystem : SharedPinpointerSystem + { + [Dependency] private readonly IEyeManager _eyeManager = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(HandleCompState); + } + + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + // we want to show pinpointers arrow direction relative + // to players eye rotation (like it was in SS13) + + // because eye can change it rotation anytime + // we need to update this arrow in a update loop + foreach (var uid in ActivePinpointers) + { + UpdateEyeDir(uid); + } + } + + private void HandleCompState(EntityUid uid, PinpointerComponent pinpointer, ref ComponentHandleState args) + { + if (args.Current is not PinpointerComponentState state) return; + SetActive(uid, state.IsActive, pinpointer); + SetDirection(uid, state.DirectionToTarget, pinpointer); + SetDistance(uid, state.DistanceToTarget, pinpointer); + + UpdateAppearance(uid, pinpointer); + UpdateEyeDir(uid, pinpointer); + } + + private void UpdateAppearance(EntityUid uid, PinpointerComponent? pinpointer = null, + AppearanceComponent? appearance = null) + { + if (!Resolve(uid, ref pinpointer, ref appearance)) + return; + + appearance.SetData(PinpointerVisuals.IsActive, pinpointer.IsActive); + appearance.SetData(PinpointerVisuals.TargetDistance, pinpointer.DistanceToTarget); + } + + private void UpdateDirAppearance(EntityUid uid, Direction dir,PinpointerComponent? pinpointer = null, + AppearanceComponent? appearance = null) + { + if (!Resolve(uid, ref pinpointer, ref appearance)) + return; + + appearance.SetData(PinpointerVisuals.TargetDirection, dir); + } + + /// + /// Transform pinpointer arrow from world space to eye space + /// And send it to the appearance component + /// + private void UpdateEyeDir(EntityUid uid, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return; + + var worldDir = pinpointer.DirectionToTarget; + if (worldDir == Direction.Invalid) + { + UpdateDirAppearance(uid, Direction.Invalid, pinpointer); + return; + } + + var eye = _eyeManager.CurrentEye; + var angle = worldDir.ToAngle() + eye.Rotation; + var eyeDir = angle.GetDir(); + UpdateDirAppearance(uid, eyeDir, pinpointer); + } + } +} diff --git a/Content.Client/Pinpointer/PinpointerVisualizer.cs b/Content.Client/Pinpointer/PinpointerVisualizer.cs new file mode 100644 index 0000000000..28d3d918ee --- /dev/null +++ b/Content.Client/Pinpointer/PinpointerVisualizer.cs @@ -0,0 +1,60 @@ +using Content.Shared.Pinpointer; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Shared.Maths; + +namespace Content.Client.Pinpointer +{ + [UsedImplicitly] + public class PinpointerVisualizer : AppearanceVisualizer + { + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out var sprite)) + return; + + // check if pinpointer screen is active + if (!component.TryGetData(PinpointerVisuals.IsActive, out bool isActive) || !isActive) + { + sprite.LayerSetVisible(PinpointerLayers.Screen, false); + return; + } + + // check if it has direction to target + sprite.LayerSetVisible(PinpointerLayers.Screen, true); + sprite.LayerSetRotation(PinpointerLayers.Screen, Angle.Zero); + + if (!component.TryGetData(PinpointerVisuals.TargetDirection, out Direction dir) || dir == Direction.Invalid) + { + sprite.LayerSetState(PinpointerLayers.Screen, "pinonnull"); + return; + } + + // check distance to target + if (!component.TryGetData(PinpointerVisuals.TargetDistance, out Distance dis)) + dis = Distance.UNKNOWN; + + switch (dis) + { + case Distance.REACHED: + sprite.LayerSetState(PinpointerLayers.Screen, "pinondirect"); + break; + case Distance.CLOSE: + sprite.LayerSetState(PinpointerLayers.Screen, "pinonclose"); + sprite.LayerSetRotation(PinpointerLayers.Screen, dir.ToAngle()); + break; + case Distance.MEDIUM: + sprite.LayerSetState(PinpointerLayers.Screen, "pinonmedium"); + sprite.LayerSetRotation(PinpointerLayers.Screen, dir.ToAngle()); + break; + case Distance.FAR: + case Distance.UNKNOWN: + sprite.LayerSetState(PinpointerLayers.Screen, "pinonfar"); + sprite.LayerSetRotation(PinpointerLayers.Screen, dir.ToAngle()); + break; + } + } + } +} diff --git a/Content.Server/Pinpointer/ServerPinpointerSystem.cs b/Content.Server/Pinpointer/ServerPinpointerSystem.cs new file mode 100644 index 0000000000..a51348e9d9 --- /dev/null +++ b/Content.Server/Pinpointer/ServerPinpointerSystem.cs @@ -0,0 +1,158 @@ +using Content.Shared.Interaction; +using Content.Shared.Pinpointer; +using Content.Shared.Whitelist; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using System.Collections.Generic; +using System.Linq; + +namespace Content.Server.Pinpointer +{ + public sealed class ServerPinpointerSystem : SharedPinpointerSystem + { + [Dependency] private readonly IEntityLookup _entityLookup = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnUseInHand); + } + + private void OnUseInHand(EntityUid uid, PinpointerComponent component, UseInHandEvent args) + { + TogglePinpointer(uid, component); + + // try to find target from whitelist + if (component.IsActive && component.Whitelist != null) + { + var target = FindTargetFromWhitelist(uid, component.Whitelist); + SetTarget(uid, target, component); + } + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + // because target or pinpointer can move + // we need to update pinpointers arrow each frame + foreach (var uid in ActivePinpointers) + { + UpdateDirectionToTarget(uid); + } + } + + /// + /// Try to find the closest entity from whitelist on a current map + /// Will return null if can't find anything + /// + private EntityUid? FindTargetFromWhitelist(EntityUid uid, EntityWhitelist whitelist, + ITransformComponent? transform = null) + { + if (!Resolve(uid, ref transform)) + return null; + + var mapId = transform.MapID; + var ents = _entityLookup.GetEntitiesInMap(mapId); + + // sort all entities in distance increasing order + var l = new SortedList(); + foreach (var e in ents) + { + if (whitelist.IsValid(e)) + { + var dist = (e.Transform.WorldPosition - transform.WorldPosition).LengthSquared; + l.TryAdd(dist, e.Uid); + } + } + + // return uid with a smallest distacne + return l.Count > 0 ? l.First().Value : null; + } + + /// + /// 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.IsActive) + UpdateDirectionToTarget(uid, pinpointer); + } + + /// + /// Update direction from pinpointer to selected target (if it was set) + /// + private void UpdateDirectionToTarget(EntityUid uid, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return; + + var target = pinpointer.Target; + if (target == null || !EntityManager.EntityExists(target.Value)) + { + SetDirection(uid, Direction.Invalid, pinpointer); + SetDistance(uid, Distance.UNKNOWN, pinpointer); + return; + } + + var dirVec = CalculateDirection(uid, target.Value); + if (dirVec != null) + { + var dir = dirVec.Value.GetDir(); + SetDirection(uid, dir, pinpointer); + var dist = CalculateDistance(uid, dirVec.Value, pinpointer); + SetDistance(uid, dist, pinpointer); + } + else + { + SetDirection(uid, Direction.Invalid, pinpointer); + SetDistance(uid, Distance.UNKNOWN, pinpointer); + } + } + + /// + /// Calculate direction from pinUid to trgUid + /// + /// Null if failed to caluclate distance between two entities + private Vector2? CalculateDirection(EntityUid pinUid, EntityUid trgUid) + { + // check if entities have transform component + if (!EntityManager.TryGetComponent(pinUid, out ITransformComponent? pin)) + return null; + if (!EntityManager.TryGetComponent(trgUid, out ITransformComponent? trg)) + return null; + + // check if they are on same map + if (pin.MapID != trg.MapID) + return null; + + // get world direction vector + var dir = (trg.WorldPosition - pin.WorldPosition); + return dir; + } + + private Distance CalculateDistance(EntityUid uid, Vector2 vec, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return Distance.UNKNOWN; + + var dist = vec.Length; + if (dist <= pinpointer.ReachedDistance) + return Distance.REACHED; + else if (dist <= pinpointer.CloseDistance) + return Distance.CLOSE; + else if (dist <= pinpointer.MediumDistance) + return Distance.MEDIUM; + else + return Distance.FAR; + } + } +} diff --git a/Content.Shared/Pinpointer/PinpointerComponent.cs b/Content.Shared/Pinpointer/PinpointerComponent.cs new file mode 100644 index 0000000000..ae107fac65 --- /dev/null +++ b/Content.Shared/Pinpointer/PinpointerComponent.cs @@ -0,0 +1,54 @@ +using System; +using Content.Shared.Whitelist; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Maths; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Shared.Pinpointer +{ + [RegisterComponent] + [NetworkedComponent] + [Friend(typeof(SharedPinpointerSystem))] + public class PinpointerComponent : Component + { + public override string Name => "Pinpointer"; + + [DataField("whitelist")] + public EntityWhitelist? Whitelist; + + [DataField("mediumDistance")] + public float MediumDistance = 16f; + + [DataField("closeDistance")] + public float CloseDistance = 8f; + + [DataField("reachedDistance")] + public float ReachedDistance = 1f; + + public EntityUid? Target = null; + public bool IsActive = false; + public Direction DirectionToTarget = Direction.Invalid; + public Distance DistanceToTarget = Distance.UNKNOWN; + } + + [Serializable, NetSerializable] + public sealed class PinpointerComponentState : ComponentState + { + public bool IsActive; + public Direction DirectionToTarget; + public Distance DistanceToTarget; + } + + [Serializable, NetSerializable] + public enum Distance : byte + { + UNKNOWN, + REACHED, + CLOSE, + MEDIUM, + FAR + } +} diff --git a/Content.Shared/Pinpointer/PinpointerVisuals.cs b/Content.Shared/Pinpointer/PinpointerVisuals.cs new file mode 100644 index 0000000000..46ee4a286e --- /dev/null +++ b/Content.Shared/Pinpointer/PinpointerVisuals.cs @@ -0,0 +1,19 @@ +using Robust.Shared.Serialization; +using System; + +namespace Content.Shared.Pinpointer +{ + [Serializable, NetSerializable] + public enum PinpointerVisuals : byte + { + IsActive, + TargetDirection, + TargetDistance + } + + public enum PinpointerLayers : byte + { + Base, + Screen + } +} diff --git a/Content.Shared/Pinpointer/SharedPinpointerSystem.cs b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs new file mode 100644 index 0000000000..ea553098ef --- /dev/null +++ b/Content.Shared/Pinpointer/SharedPinpointerSystem.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using Robust.Shared.GameObjects; +using Robust.Shared.GameStates; +using Robust.Shared.Maths; + +namespace Content.Shared.Pinpointer +{ + public abstract class SharedPinpointerSystem : EntitySystem + { + protected readonly HashSet ActivePinpointers = new(); + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(GetCompState); + } + + private void GetCompState(EntityUid uid, PinpointerComponent pinpointer, ref ComponentGetState args) + { + args.State = new PinpointerComponentState + { + IsActive = pinpointer.IsActive, + DirectionToTarget = pinpointer.DirectionToTarget, + DistanceToTarget = pinpointer.DistanceToTarget + }; + } + + /// + /// Manually set distance from pinpointer to target + /// + public void SetDistance(EntityUid uid, Distance distance, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return; + + if (distance == pinpointer.DistanceToTarget) + return; + + pinpointer.DistanceToTarget = distance; + pinpointer.Dirty(); + } + + /// + /// Manually set pinpointer arrow direction + /// + public void SetDirection(EntityUid uid, Direction directionToTarget, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return; + + if (directionToTarget == pinpointer.DirectionToTarget) + return; + + pinpointer.DirectionToTarget = directionToTarget; + pinpointer.Dirty(); + } + + /// + /// Activate/deactivate pinpointer screen. If it has target it will start tracking it. + /// + public void SetActive(EntityUid uid, bool isActive, PinpointerComponent? pinpointer = null) + { + if (!Resolve(uid, ref pinpointer)) + return; + if (isActive == pinpointer.IsActive) + return; + + // add-remove pinpointer from update list + if (isActive) + ActivePinpointers.Add(uid); + else + ActivePinpointers.Remove(uid); + + pinpointer.IsActive = isActive; + pinpointer.Dirty(); + } + + + /// + /// 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; + } + } +} diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml index f21a34b141..3e5bb0caf7 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml @@ -35,6 +35,8 @@ contents: - id: NukeDisk prob: 1 + - id: PinpointerNuclear + prob: 1 - id: CaptainIDCard prob: 1 - id: ClothingHeadHatCaptain diff --git a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml new file mode 100644 index 0000000000..cf2317ca04 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml @@ -0,0 +1,33 @@ +- type: entity + name: pinpointer + description: A handheld tracking device that locks onto certain signals. + parent: BaseItem + id: PinpointerBase + abstract: true + components: + - type: Transform + noRot: True + - type: Sprite + netsync: false + sprite: Objects/Devices/pinpointer.rsi + layers: + - state: pinpointer + map: ["enum.PinpointerLayers.Base"] + - state: pinonnull + map: ["enum.PinpointerLayers.Screen"] + - type: Item + sprite: Objects/Devices/pinpointer.rsi + - type: Pinpointer + - type: Appearance + visuals: + - type: PinpointerVisualizer + +- type: entity + name: pinpointer + id: PinpointerNuclear + parent: PinpointerBase + components: + - type: Pinpointer + whitelist: + tags: + - NukeDisk diff --git a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml index 62783ee50c..092c12ce9d 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/dat_fukken_disk.yml @@ -4,6 +4,9 @@ id: NukeDisk description: A nuclear auth disk, capable of arming a nuke if used along with a code. Note from nanotrasen reads "THIS IS YOUR MOST IMPORTANT POSESSION, SECURE DAT FUKKEN DISK!" components: + - type: Tag + tags: + - NukeDisk - type: Sprite netsync: false sprite: Objects/Misc/nukedisk.rsi @@ -14,6 +17,17 @@ state: icon - type: entity - parent: NukeDisk + name: nuclear authentication disk + parent: BaseItem id: NukeDiskFake + suffix: Fake description: A nuclear auth disk, capable of.. WAIT THIS IS JUST PAINTED PLASTIC, FUCK- + components: + - type: Sprite + netsync: false + sprite: Objects/Misc/nukedisk.rsi + state: icon + - type: Item + size: 12 + sprite: Objects/Misc/nukedisk.rsi + state: icon diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index e7edf9fede..d7375805af 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -223,3 +223,5 @@ - type: Tag id: HideContextMenu +- type: Tag + id: NukeDisk diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/inhand-left.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..d36482284918bf238031c5b5cb133e7bf5efa649 GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=-JULvAr*7p-rC4}*no%SfWO<7 zl6g+dDVEEFCMtybND7pMudEVSVr9e#RD9#iVxu)%%lgXS@71Xe%bR4QeR$H7QW;OX z?tMv5dhTRB<&{{a7Ha!3KUgXt_RAZ!DXV_{Du2oZ)XBhbK_NU=FkzW$!>G0n3E28TOA$~|5ET-G@yGyworHb|TR literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/inhand-right.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..8f268d6a75fe8974c46192a4e38836e904eb6c96 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=y`CO9tRTSZFiE+{ zYJL;*lcK^@&7#JSTK{s4f_ECccRp+PnT!sW}FpOvYfwo_P%AB z^WM04pF3|RH s&I@3i>0hH8;-I-d)M-Yf4Ff~v+12`*XI0$zG(qY;UHx3vIVCg!0DnzL!vFvP literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json b/Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json new file mode 100644 index 0000000000..5e05af6671 --- /dev/null +++ b/Resources/Textures/Objects/Devices/pinpointer.rsi/meta.json @@ -0,0 +1,162 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/59f2a4e10e5ba36033c9734ddebfbbdc6157472d", + "states": [ + { + "name": "pinonalert", + "directions": 8, + "delays": [ + [ + 0.2, + 0.2 + ], + [ + 0.2, + 0.2 + ], + [ + 0.2, + 0.2 + ], + [ + 0.2, + 0.2 + ], + [ + 0.2, + 0.2 + ], + [ + 0.2, + 0.2 + ], + [ + 0.2, + 0.2 + ], + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinonalertdirect", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinonalertnull", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinonclose", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinondirect", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinondirectlarge", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinondirectsmall", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinondirectxtrlarge", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinonfar", + "delays": [ + [ + 0.6, + 0.2 + ] + ] + }, + { + "name": "pinonmedium", + "delays": [ + [ + 0.4, + 0.2 + ] + ] + }, + { + "name": "pinonnull", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "pinpointer" + }, + { + "name": "pinpointer_crew" + }, + { + "name": "pinpointer_crewprox" + }, + { + "name": "pinpointer_syndicate" + }, + { + "name": "pinpointer_way" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonalert.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonalert.png new file mode 100644 index 0000000000000000000000000000000000000000..39e73ee2664ae4d38ea4bf7fd9aa9a5a871fb265 GIT binary patch literal 577 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrVB+v}aSW-L^Y-q=+`|e23<29; ziF}l}t9&@EzwhCii*<@iPh@o+jNyJ?8@-V~o}vEEMjfDD1_qvYOP@T-y=^x?cJsRI zi}}-j#N3;I?|(2Ju+q0{V)!)xMow~Pf_cD`z*V)dSE;ae^llz6L zYTUerr78y)e|o>4%ktBEy=T+*TkSIgr9SLcUC=(IpxWDECFbu;U=a59TlI z8U{&!vY6Gct1vEFUA)Nqa#glu{$|O9C5}H&W)z0KW&FnW_>5`AdUwBd-=*$scE4~> zPGyVxh1%V3r)7OFid?^Y>8tdU$-OaEpKkPLZDZ-Vp!3k&t$VX4Q;(U(`5uw==N*vk z+Yhmi%UMmG5ro30GAuUr)-ZMYbM-G{)wSo(^C~K2+Z3iR5@E^geeluU07aOhg>&?9vo4e0j?B2P{ zKxLPM;wp#aDLbaN`L6TKj5y+X%TvqmZDmDCiepaK)~gla-`P8C?Dmyc{*rupQ}vvN u|N3|Q0-4{K&We4!&FtgH1Vj)!c;0XaJm-mwJaOoQjXlq^8|btUBnUue=?p?7Wm2? s<=VU8wa}caHKK-9r|p}8CNo_7!eo@HD#Y=5$xjg1)78&qol`;+051edSO5S3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonalertnull.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonalertnull.png new file mode 100644 index 0000000000000000000000000000000000000000..1556d82c76d9140d150dbab6ef0b5e29fbb2f42e GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQnNi>978JRyuEUkw?ToYA<)!M zF?k33;Z5zy52UJ^OkDVNR|M`aXIk{leZgy>@`m_Vru@exwwuh`bN+QUN9CJ2!L`B3 zv!BbvADgoC%jrd3_7Or88T+4wPd+Mt*3^eLLvTl{Sg*XUe(k~!N3Jv&b*f7hm9b}p z$~GEJRKN0$?K59R^~26ecAtCq>wbG@bNJRdeH8@S!_Z)Ui?QELN5ZF2XA_9;>FVdQ I&MBb@0PM3)^Z)<= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonclose.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonclose.png new file mode 100644 index 0000000000000000000000000000000000000000..d652e4cd02a15fd1ae265b6af6038803243d74d2 GIT binary patch literal 4979 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 CNrOZH literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirect.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirect.png new file mode 100644 index 0000000000000000000000000000000000000000..c2ac6e44e2720d0b2477e1a345005e6df91d4c0b GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQn{Wkjv*Cu-d=U&I-nrnd~wV5 z8NcOqpJ#;U?aCNjzIkkvv)CG%@-H4)#vX4 OaXnrAT-G@yGywq0o<45? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectlarge.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectlarge.png new file mode 100644 index 0000000000000000000000000000000000000000..c8b1fa4875244eb86bcb5bf3ef87c72bbcb733c8 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQYD@)jv*Cu-d;J#+n~VH`Y`Lx zqqp`^&o2ZE>mL#6iTb%;xSdH?FVdQ&MBb@0PE90Y5)KL literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectsmall.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectsmall.png new file mode 100644 index 0000000000000000000000000000000000000000..ab7940efd992708c0fd020969b51f7d50b2d7e9a GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQt_THjv*Cu-d-`}Yf#`}z3|Gk z>i^=eGFFxrk_V0`yw}xXy*1x~g@HjQGh1`rs>dtUjAx(w^XuQ<{d4OD4xD&)re<~j z`4aX5Ui)f}yNn@MbLU>YAUvb?2gm#cK*JkM=O*nJ6skU=A_n9!c)I$ztaD0e0szd< BH)8+* literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectxtrlarge.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinondirectxtrlarge.png new file mode 100644 index 0000000000000000000000000000000000000000..5db693402ca49f731e6bc1701c19f6865e16bc8f GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfZzpjv*Cu-d;5nYB1n%x%i@@ zd++~?-(;d9B}*45Ui|OHHpxLSiW#V~F0)hR_PzT>Dy`?%?5jU*<8nzg&AK>br)kuM z?0=eeyFM`NYhw(tUm(TYA$I5Qx6OHtSES}_jRfjsu#lahBYaeU&w(!>o~Nsy%Q~lo FCIC~xIo|*P literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonfar.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonfar.png new file mode 100644 index 0000000000000000000000000000000000000000..fd0fbf51ac65ccbdeb482f6c119788c62dc22d05 GIT binary patch literal 230 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonnull.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinonnull.png new file mode 100644 index 0000000000000000000000000000000000000000..a309d053e59380119831bb4d0cc1aec835b68b95 GIT binary patch literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQnj8gjv*Cu-d@=&*r34E_R#;l zW`cTKs(Os`>H@JKfmJVlha6y3{No8!dO$zdcy4s|^r^v`d;hN4I=%Q@aBNL8I|}bNgm}HUe_zL* e5ojDk#|yU2KcpnC-}!JE#PxLbb6Mw<&;$UGNk-rR literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer.png new file mode 100644 index 0000000000000000000000000000000000000000..24c7e0dc68dad873bf52f166866760697d1ebb0c GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ+nz3tAr*6y6C_v{Cx}d7c$A#< zZ?=Tw-~Rs2pY{oT28Kq9Rz2-;S@k>r^ikh{ix2bTJ-0P4V9wdO>%eQY` zAKor1d|b*RtjV{4Ric#PtW3e#+sO&C4_>~s+`v~cW3v4QJ_RwJ3Mqw^3Qqbd9~k}p z{o9(Q&4qP1SB8lvFo&$05s@G-wBN5kv>9=XuXEf6a!ys}To+U=l*1go+L14D1Q WT|-nB=PsZ(89ZJ6T-G@yGywqo2x;p8 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_crew.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_crew.png new file mode 100644 index 0000000000000000000000000000000000000000..af24601880eb3682dde00790b36a3e3f32fc8a73 GIT binary patch literal 265 zcmV+k0rvihP)`bVLpcTZ_ikJMSm5#I<+2HIktSTc z36lmV5Q>+sj{bhtGHLHJWXJRdK*eCpj4 P00000NkvXXu0mjfh!1k< literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_crewprox.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_crewprox.png new file mode 100644 index 0000000000000000000000000000000000000000..c1472880855decc6df75700e624be335b1c9b151 GIT binary patch literal 315 zcmV-B0mS}^P)S)RLF1u0|UdU z)je3npFF+?XUoVcp-Rfz;dKNPDGne8NLd6iFfcGM#04i3rJm{zfPsYp#04(R9Kcw- ze_$QJ@aoP0JAg<)GY5<&LShpkNd*ylAp^_vSOF{%QmZ6m#} z`#$m{u0z!mP=RRz_uSSBJYLVW0^a+z0#cUGfOr*;Zo-rjwrvA&(kdQVuYi08L>(AP n{=rcP*csry)7keGMfrc;1p+uXgxLLX00000NkvXXu0mjf19oCY literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_way.png b/Resources/Textures/Objects/Devices/pinpointer.rsi/pinpointer_way.png new file mode 100644 index 0000000000000000000000000000000000000000..478750439f097c817e1d7be098bc6420c1916c15 GIT binary patch literal 266 zcmV+l0rmcgP)F@* zu~s%=DJ8@htJ!7&0DyU((M$;8(q=qrFN-{}Ia@Dg@k zLefL@{m9hVmT<2h4hbCTgOn1QK?PoA0>dznhp+33=9=r6H2n>%jv0nwo-rImBuVhT Q+W-In07*qoM6N<$f(`O<4*&oF literal 0 HcmV?d00001