diff --git a/Content.Client/Content.Client.csproj b/Content.Client/Content.Client.csproj
index 24f52e8351..7e484e6eee 100644
--- a/Content.Client/Content.Client.csproj
+++ b/Content.Client/Content.Client.csproj
@@ -90,6 +90,7 @@
+
diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs
index 6b9bcbdcd4..ac22770bb2 100644
--- a/Content.Client/EntryPoint.cs
+++ b/Content.Client/EntryPoint.cs
@@ -3,7 +3,7 @@ using Content.Client.GameObjects.Components.Actor;
using Content.Client.GameObjects.Components.Clothing;
using Content.Client.GameObjects.Components.Construction;
using Content.Client.GameObjects.Components.Power;
-using Content.Client.GameObjects.Components.SmoothWalling;
+using Content.Client.GameObjects.Components.IconSmoothing;
using Content.Client.GameObjects.Components.Storage;
using Content.Client.GameObjects.Components.Weapons.Ranged;
using Content.Client.GameTicking;
diff --git a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs
index 18db2fb3e2..e416f4d69c 100644
--- a/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs
+++ b/Content.Client/GameObjects/Components/IconSmoothing/IconSmoothComponent.cs
@@ -1,18 +1,14 @@
-using System;
-using System.Collections.Generic;
-using Content.Shared.GameObjects;
+using System.Diagnostics.CodeAnalysis;
+using Content.Client.GameObjects.EntitySystems;
+using JetBrains.Annotations;
using SS14.Client.Interfaces.GameObjects.Components;
using SS14.Shared.GameObjects;
using SS14.Shared.GameObjects.Components.Transform;
-using SS14.Shared.Interfaces.GameObjects;
-using SS14.Shared.Interfaces.Map;
-using SS14.Shared.IoC;
using SS14.Shared.Map;
-using SS14.Shared.Maths;
using SS14.Shared.Serialization;
using static SS14.Client.GameObjects.SpriteComponent;
-namespace Content.Client.GameObjects.Components.SmoothWalling
+namespace Content.Client.GameObjects.Components.IconSmoothing
{
// TODO: Potential improvements:
// Defer updating of these.
@@ -25,212 +21,115 @@ namespace Content.Client.GameObjects.Components.SmoothWalling
/// To use, set base equal to the prefix of the corner states in the sprite base RSI.
/// Any objects with the same key will connect.
///
- public class IconSmoothComponent : Component, IComponentDebug
+ public sealed class IconSmoothComponent : Component
{
+ private string _smoothKey;
+ private string _stateBase;
+ private IconSmoothingMode _mode;
+
public override string Name => "IconSmooth";
- ISpriteComponent Sprite;
- SnapGridComponent SnapGrid;
-
- ///
- /// Prepended to the RSI state.
- ///
- string StateBase;
+ internal ISpriteComponent Sprite { get; private set; }
+ internal SnapGridComponent SnapGrid { get; private set; }
+ private (GridId, MapIndices) _lastPosition;
///
/// We will smooth with other objects with the same key.
///
- string SmoothKey;
+ public string SmoothKey => _smoothKey;
- IconSmoothComponent[] Neighbors = new IconSmoothComponent[8];
- // "Use an array".
- // Nah. I'm too lazy. This is easy to understand compared to the enum value fuckery if I used an array.
- // Deal with it.
- CornerFill CornerSE;
- CornerFill CornerNE;
- CornerFill CornerNW;
- CornerFill CornerSW;
+ ///
+ /// Prepended to the RSI state.
+ ///
+ public string StateBase => _stateBase;
+
+ ///
+ /// Mode that controls how the icon should be selected.
+ ///
+ public IconSmoothingMode Mode => _mode;
+
+ ///
+ /// Used by to reduce redundant updates.
+ ///
+ internal int UpdateGeneration { get; set; }
public override void Initialize()
{
base.Initialize();
- var state0 = $"{StateBase}0";
SnapGrid = Owner.GetComponent();
Sprite = Owner.GetComponent();
- Sprite.LayerMapSet(CornerLayers.SE, Sprite.AddLayerState(state0));
- Sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None);
- Sprite.LayerMapSet(CornerLayers.NE, Sprite.AddLayerState(state0));
- Sprite.LayerSetDirOffset(CornerLayers.NE, DirectionOffset.CounterClockwise);
- Sprite.LayerMapSet(CornerLayers.NW, Sprite.AddLayerState(state0));
- Sprite.LayerSetDirOffset(CornerLayers.NW, DirectionOffset.Flip);
- Sprite.LayerMapSet(CornerLayers.SW, Sprite.AddLayerState(state0));
- Sprite.LayerSetDirOffset(CornerLayers.SW, DirectionOffset.Clockwise);
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
- serializer.DataFieldCached(ref StateBase, "base", "");
- serializer.DataFieldCached(ref SmoothKey, "key", null);
+
+ serializer.DataFieldCached(ref _stateBase, "base", "");
+ serializer.DataFieldCached(ref _smoothKey, "key", null);
+ serializer.DataFieldCached(ref _mode, "mode", IconSmoothingMode.Corners);
}
public override void Startup()
{
base.Startup();
- SnapGrid.OnPositionChanged += SnapGridPositionChanged;
-
- UpdateConnections(true);
- UpdateIcon();
+ SnapGrid.OnPositionChanged += SnapGridOnPositionChanged;
+ Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(null, SnapGrid.Offset, Mode));
+ var state0 = $"{StateBase}0";
+ if (Mode == IconSmoothingMode.Corners)
+ {
+ Sprite.LayerMapSet(CornerLayers.SE, Sprite.AddLayerState(state0));
+ Sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None);
+ Sprite.LayerMapSet(CornerLayers.NE, Sprite.AddLayerState(state0));
+ Sprite.LayerSetDirOffset(CornerLayers.NE, DirectionOffset.CounterClockwise);
+ Sprite.LayerMapSet(CornerLayers.NW, Sprite.AddLayerState(state0));
+ Sprite.LayerSetDirOffset(CornerLayers.NW, DirectionOffset.Flip);
+ Sprite.LayerMapSet(CornerLayers.SW, Sprite.AddLayerState(state0));
+ Sprite.LayerSetDirOffset(CornerLayers.SW, DirectionOffset.Clockwise);
+ }
}
public override void Shutdown()
{
+ SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
+ Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
+
base.Shutdown();
-
- SnapGrid.OnPositionChanged -= SnapGridPositionChanged;
- SayGoodbyes();
}
- void SayGoodbyes()
+ private void SnapGridOnPositionChanged()
{
- foreach (var neighbor in Neighbors)
- {
- // Goodbye neighbor.
- neighbor?.UpdateConnections(false);
- neighbor?.UpdateIcon();
- }
+ Owner.EntityManager.RaiseEvent(Owner, new IconSmoothDirtyEvent(_lastPosition, SnapGrid.Offset, Mode));
+ _lastPosition = (Owner.Transform.GridID, SnapGrid.Position);
}
- void SnapGridPositionChanged()
- {
- SayGoodbyes();
- UpdateConnections(true);
- UpdateIcon();
- }
-
- void UpdateIcon()
- {
- // Try to turn this into a loop without hard to understand bit fuckery or 20 lines of helper functions.
- // Challenge: do it in less lines.
- // I dare you.
- // No cheating like putting everything on a single line. Proper code conventions.
- // This comment does not count, btw.
-
- Sprite.LayerSetState(CornerLayers.NE, $"{StateBase}{(int)CornerNE}");
- Sprite.LayerSetState(CornerLayers.SE, $"{StateBase}{(int)CornerSE}");
- Sprite.LayerSetState(CornerLayers.SW, $"{StateBase}{(int)CornerSW}");
- Sprite.LayerSetState(CornerLayers.NW, $"{StateBase}{(int)CornerNW}");
- }
-
- void UpdateConnections(bool propagate)
- {
- for (int i = 0; i < Neighbors.Length; i++)
- {
- var found = false;
- var dir = (Direction)i;
- foreach (var entity in SnapGrid.GetInDir(dir))
- {
- if (entity.TryGetComponent(out IconSmoothComponent smooth) && smooth.SmoothKey == SmoothKey)
- {
- Neighbors[i] = smooth;
- if (propagate)
- {
- smooth.UpdateConnections(false);
- smooth.UpdateIcon();
- }
- // Temptation to use goto: 10.
- found = true;
- break;
- }
- }
-
- if (!found)
- {
- Neighbors[i] = null;
- }
- }
-
- CornerNE = CornerSE = CornerNW = CornerSW = CornerFill.None;
-
- // "Use a loop".
- // Well screw that I did the exact same thing while writing lighting corner population code in BYOND.
- // This is 10x easier to understand and write than a complex loop working with the internet mapping of direction flags.
- if (Neighbors[(int)Direction.North] != null)
- {
- CornerNE |= CornerFill.CounterClockwise;
- CornerNW |= CornerFill.Clockwise;
- }
- if (Neighbors[(int)Direction.NorthEast] != null)
- {
- CornerNE |= CornerFill.Diagonal;
- }
- if (Neighbors[(int)Direction.East] != null)
- {
- CornerNE |= CornerFill.Clockwise;
- CornerSE |= CornerFill.CounterClockwise;
- }
- if (Neighbors[(int)Direction.SouthEast] != null)
- {
- CornerSE |= CornerFill.Diagonal;
- }
- if (Neighbors[(int)Direction.South] != null)
- {
- CornerSE |= CornerFill.Clockwise;
- CornerSW |= CornerFill.CounterClockwise;
- }
- if (Neighbors[(int)Direction.SouthWest] != null)
- {
- CornerSW |= CornerFill.Diagonal;
- }
- if (Neighbors[(int)Direction.West] != null)
- {
- CornerSW |= CornerFill.Clockwise;
- CornerNW |= CornerFill.CounterClockwise;
- }
- if (Neighbors[(int)Direction.NorthWest] != null)
- {
- CornerNW |= CornerFill.Diagonal;
- }
- }
-
- public string GetDebugString()
- {
- return string.Format(
- "N/NE/E/SE/S/SW/W/NW: {0}/{1}/{2}/{3}/{4}/{5}/{6}/{7} cfill NE/SE/SW/NW: {8}/{9}/{10}/{11}",
- Neighbors[(int)Direction.North]?.Owner?.Uid,
- Neighbors[(int)Direction.NorthEast]?.Owner?.Uid,
- Neighbors[(int)Direction.East]?.Owner?.Uid,
- Neighbors[(int)Direction.SouthEast]?.Owner?.Uid,
- Neighbors[(int)Direction.South]?.Owner?.Uid,
- Neighbors[(int)Direction.SouthWest]?.Owner?.Uid,
- Neighbors[(int)Direction.West]?.Owner?.Uid,
- Neighbors[(int)Direction.NorthWest]?.Owner?.Uid,
- CornerNE, CornerSE, CornerSW, CornerNW
- );
- }
-
- enum CornerLayers
+ [SuppressMessage("ReSharper", "InconsistentNaming")]
+ public enum CornerLayers
{
SE,
NE,
NW,
SW,
}
+ }
- [Flags]
- enum CornerFill : byte
- {
- // These values are pulled from Baystation12.
- // I'm too lazy to convert the state names.
- None = 0,
- // The cardinal tile counter-clockwise of this corner is filled.
- CounterClockwise = 1,
- // The diagonal tile in the direction of this corner.
- Diagonal = 2,
- // The cardinal tile clockwise of this corner is filled.
- Clockwise = 4,
- }
+ ///
+ /// Controls the mode with which icon smoothing is calculated.
+ ///
+ [PublicAPI]
+ public enum IconSmoothingMode
+ {
+ ///
+ /// Each icon is made up of 4 corners, each of which can get a different state depending on
+ /// adjacent entities clockwise, counter-clockwise and diagonal with the corner.
+ ///
+ Corners,
+
+ ///
+ /// There are 16 icons, only one of which is used at once.
+ /// The icon selected is a bit field made up of the cardinal direction flags that have adjacent entities.
+ ///
+ CardinalFlags,
}
}
diff --git a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs
new file mode 100644
index 0000000000..77aa222196
--- /dev/null
+++ b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs
@@ -0,0 +1,304 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Content.Client.GameObjects.Components.IconSmoothing;
+using JetBrains.Annotations;
+using SS14.Client.Interfaces.GameObjects.Components;
+using SS14.Shared.GameObjects;
+using SS14.Shared.GameObjects.Components.Transform;
+using SS14.Shared.GameObjects.Systems;
+using SS14.Shared.Interfaces.GameObjects;
+using SS14.Shared.Interfaces.Map;
+using SS14.Shared.IoC;
+using SS14.Shared.Map;
+using SS14.Shared.Maths;
+
+namespace Content.Client.GameObjects.EntitySystems
+{
+ ///
+ /// Entity system implementing the logic for
+ ///
+ [UsedImplicitly]
+ internal sealed class IconSmoothSystem : EntitySystem
+ {
+#pragma warning disable 649
+ [Dependency] private readonly IMapManager _mapManager;
+#pragma warning restore 649
+
+ private readonly Queue _dirtyEntities = new Queue();
+
+ private int _generation;
+
+ public override void SubscribeEvents()
+ {
+ base.SubscribeEvents();
+
+ SubscribeEvent(HandleDirtyEvent);
+ }
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ IoCManager.InjectDependencies(this);
+ }
+
+ public override void FrameUpdate(float frameTime)
+ {
+ base.FrameUpdate(frameTime);
+
+ if (_dirtyEntities.Count == 0)
+ {
+ return;
+ }
+
+ _generation += 1;
+
+ // Performance: This could be spread over multiple updates, or made parallel.
+ while (_dirtyEntities.Count > 0)
+ {
+ CalculateNewSprite(_dirtyEntities.Dequeue());
+ }
+ }
+
+ private void HandleDirtyEvent(object sender, IconSmoothDirtyEvent ev)
+ {
+ // Yes, we updates ALL smoothing entities surrounding us even if they would never smooth with us.
+ // This is simpler to implement. If you want to optimize it be my guest.
+ if (sender is IEntity senderEnt && senderEnt.IsValid() &&
+ senderEnt.HasComponent())
+ {
+ var snapGrid = senderEnt.GetComponent();
+
+ _dirtyEntities.Enqueue(senderEnt);
+ AddValidEntities(snapGrid.GetInDir(Direction.North));
+ AddValidEntities(snapGrid.GetInDir(Direction.South));
+ AddValidEntities(snapGrid.GetInDir(Direction.East));
+ AddValidEntities(snapGrid.GetInDir(Direction.West));
+ if (ev.Mode == IconSmoothingMode.Corners)
+ {
+
+ AddValidEntities(snapGrid.GetInDir(Direction.NorthEast));
+ AddValidEntities(snapGrid.GetInDir(Direction.SouthEast));
+ AddValidEntities(snapGrid.GetInDir(Direction.SouthWest));
+ AddValidEntities(snapGrid.GetInDir(Direction.NorthWest));
+ }
+ }
+ else if (ev.LastPosition.HasValue)
+ {
+ // Entity is no longer valid, update around the last position it was at.
+ var grid = _mapManager.GetGrid(ev.LastPosition.Value.grid);
+ var pos = ev.LastPosition.Value.pos;
+
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, 0), ev.Offset));
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, 0), ev.Offset));
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(0, 1), ev.Offset));
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(0, -1), ev.Offset));
+ if (ev.Mode == IconSmoothingMode.Corners)
+ {
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, 1), ev.Offset));
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, -1), ev.Offset));
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(-1, 1), ev.Offset));
+ AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, -1), ev.Offset));
+ }
+ }
+ }
+
+ private void AddValidEntities(IEnumerable candidates)
+ {
+ foreach (var entity in candidates)
+ {
+ if (entity.HasComponent())
+ {
+ _dirtyEntities.Enqueue(entity);
+ }
+ }
+ }
+
+ private void AddValidEntities(IEnumerable candidates)
+ {
+ AddValidEntities(candidates.Select(c => c.Owner));
+ }
+
+ private void CalculateNewSprite(IEntity entity)
+ {
+ // The generation check prevents updating an entity multiple times per tick.
+ // As it stands now, it's totally possible for something to get queued twice.
+ // Generation on the component is set after an update so we can cull updates that happened this generation.
+ if (!entity.IsValid()
+ || !entity.TryGetComponent(out IconSmoothComponent smoothing)
+ || smoothing.UpdateGeneration == _generation)
+ {
+ return;
+ }
+
+ var sprite = smoothing.Sprite;
+ var snapGrid = smoothing.SnapGrid;
+
+ switch (smoothing.Mode)
+ {
+ case IconSmoothingMode.Corners:
+ _calculateNewSpriteCorers(smoothing, snapGrid, sprite);
+ break;
+
+ case IconSmoothingMode.CardinalFlags:
+ _calculateNewSpriteCardinal(smoothing, snapGrid, sprite);
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+
+ smoothing.UpdateGeneration = _generation;
+ }
+
+ private static void _calculateNewSpriteCardinal(IconSmoothComponent smoothing, SnapGridComponent snapGrid,
+ ISpriteComponent sprite)
+ {
+ var dirs = CardinalConnectDirs.None;
+
+ if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.North)))
+ dirs |= CardinalConnectDirs.North;
+ if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.South)))
+ dirs |= CardinalConnectDirs.South;
+ if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.East)))
+ dirs |= CardinalConnectDirs.East;
+ if (MatchingEntity(smoothing, snapGrid.GetInDir(Direction.West)))
+ dirs |= CardinalConnectDirs.West;
+
+ sprite.LayerSetState(0, $"{smoothing.StateBase}{(int) dirs}");
+ }
+
+ private static void _calculateNewSpriteCorers(IconSmoothComponent smoothing, SnapGridComponent snapGrid,
+ ISpriteComponent sprite)
+ {
+ var n = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.North));
+ var ne = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.NorthEast));
+ var e = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.East));
+ var se = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.SouthEast));
+ var s = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.South));
+ var sw = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.SouthWest));
+ var w = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.West));
+ var nw = MatchingEntity(smoothing, snapGrid.GetInDir(Direction.NorthWest));
+
+ // ReSharper disable InconsistentNaming
+ var cornerNE = CornerFill.None;
+ var cornerSE = CornerFill.None;
+ var cornerSW = CornerFill.None;
+ var cornerNW = CornerFill.None;
+ // ReSharper restore InconsistentNaming
+
+ if (n)
+ {
+ cornerNE |= CornerFill.CounterClockwise;
+ cornerNW |= CornerFill.Clockwise;
+ }
+
+ if (ne)
+ {
+ cornerNE |= CornerFill.Diagonal;
+ }
+
+ if (e)
+ {
+ cornerNE |= CornerFill.Clockwise;
+ cornerSE |= CornerFill.CounterClockwise;
+ }
+
+ if (se)
+ {
+ cornerSE |= CornerFill.Diagonal;
+ }
+
+ if (s)
+ {
+ cornerSE |= CornerFill.Clockwise;
+ cornerSW |= CornerFill.CounterClockwise;
+ }
+
+ if (sw)
+ {
+ cornerSW |= CornerFill.Diagonal;
+ }
+
+ if (w)
+ {
+ cornerSW |= CornerFill.Clockwise;
+ cornerNW |= CornerFill.CounterClockwise;
+ }
+
+ if (nw)
+ {
+ cornerNW |= CornerFill.Diagonal;
+ }
+
+ sprite.LayerSetState(IconSmoothComponent.CornerLayers.NE, $"{smoothing.StateBase}{(int) cornerNE}");
+ sprite.LayerSetState(IconSmoothComponent.CornerLayers.SE, $"{smoothing.StateBase}{(int) cornerSE}");
+ sprite.LayerSetState(IconSmoothComponent.CornerLayers.SW, $"{smoothing.StateBase}{(int) cornerSW}");
+ sprite.LayerSetState(IconSmoothComponent.CornerLayers.NW, $"{smoothing.StateBase}{(int) cornerNW}");
+ }
+
+ [System.Diagnostics.Contracts.Pure]
+ private static bool MatchingEntity(IconSmoothComponent source, IEnumerable candidates)
+ {
+ foreach (var entity in candidates)
+ {
+ if (!entity.TryGetComponent(out IconSmoothComponent other))
+ {
+ return false;
+ }
+
+ if (other.SmoothKey == source.SmoothKey)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ [Flags]
+ private enum CardinalConnectDirs : byte
+ {
+ None = 0,
+ North = 1,
+ South = 2,
+ East = 4,
+ West = 8
+ }
+
+ [Flags]
+ private enum CornerFill : byte
+ {
+ // These values are pulled from Baystation12.
+ // I'm too lazy to convert the state names.
+ None = 0,
+
+ // The cardinal tile counter-clockwise of this corner is filled.
+ CounterClockwise = 1,
+
+ // The diagonal tile in the direction of this corner.
+ Diagonal = 2,
+
+ // The cardinal tile clockwise of this corner is filled.
+ Clockwise = 4,
+ }
+ }
+
+ ///
+ /// Event raised by a when it needs to be recalculated.
+ ///
+ public sealed class IconSmoothDirtyEvent : EntitySystemMessage
+ {
+ public IconSmoothDirtyEvent((GridId grid, MapIndices pos)? lastPosition, SnapGridOffset offset, IconSmoothingMode mode)
+ {
+ LastPosition = lastPosition;
+ Offset = offset;
+ Mode = mode;
+ }
+
+ public (GridId grid, MapIndices pos)? LastPosition { get; }
+ public SnapGridOffset Offset { get; }
+ public IconSmoothingMode Mode { get; }
+ }
+}
diff --git a/Resources/Prototypes/Entities/Power.yml b/Resources/Prototypes/Entities/Power.yml
index e9a96b26f7..7487ddadd2 100644
--- a/Resources/Prototypes/Entities/Power.yml
+++ b/Resources/Prototypes/Entities/Power.yml
@@ -6,12 +6,20 @@
- type: Clickable
- type: BoundingBox
- type: Sprite
+ netsync: false
drawdepth: BelowFloor
color: Red
- texture: Objects/eightdirwire.png
+ sprite: Objects/power_cable.rsi
+ state: cable_0
- type: Icon
texture: Objects/eightdirwire.png
- type: PowerTransfer
+ - type: SnapGrid
+ offset: Center
+ - type: IconSmooth
+ base: cable_
+ key: power_cables
+ mode: CardinalFlags
snap:
- Wire
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_0.png b/Resources/Textures/Objects/power_cable.rsi/cable_0.png
new file mode 100644
index 0000000000..580528df53
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_0.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_1.png b/Resources/Textures/Objects/power_cable.rsi/cable_1.png
new file mode 100644
index 0000000000..fdebed5fa9
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_1.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_10.png b/Resources/Textures/Objects/power_cable.rsi/cable_10.png
new file mode 100644
index 0000000000..17c40b2276
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_10.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_11.png b/Resources/Textures/Objects/power_cable.rsi/cable_11.png
new file mode 100644
index 0000000000..76b20ffa8d
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_11.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_12.png b/Resources/Textures/Objects/power_cable.rsi/cable_12.png
new file mode 100644
index 0000000000..8364d69509
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_12.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_13.png b/Resources/Textures/Objects/power_cable.rsi/cable_13.png
new file mode 100644
index 0000000000..6f03458fd3
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_13.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_14.png b/Resources/Textures/Objects/power_cable.rsi/cable_14.png
new file mode 100644
index 0000000000..6cdb9d20bc
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_14.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_15.png b/Resources/Textures/Objects/power_cable.rsi/cable_15.png
new file mode 100644
index 0000000000..d45a733324
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_15.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_2.png b/Resources/Textures/Objects/power_cable.rsi/cable_2.png
new file mode 100644
index 0000000000..ce3ffea8a4
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_2.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_3.png b/Resources/Textures/Objects/power_cable.rsi/cable_3.png
new file mode 100644
index 0000000000..2edb689b55
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_3.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_4.png b/Resources/Textures/Objects/power_cable.rsi/cable_4.png
new file mode 100644
index 0000000000..fb782f3cad
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_4.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_5.png b/Resources/Textures/Objects/power_cable.rsi/cable_5.png
new file mode 100644
index 0000000000..6e0ffe9db5
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_5.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_6.png b/Resources/Textures/Objects/power_cable.rsi/cable_6.png
new file mode 100644
index 0000000000..2d855fe035
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_6.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_7.png b/Resources/Textures/Objects/power_cable.rsi/cable_7.png
new file mode 100644
index 0000000000..e382deeda1
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_7.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_8.png b/Resources/Textures/Objects/power_cable.rsi/cable_8.png
new file mode 100644
index 0000000000..408fdf51ea
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_8.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/cable_9.png b/Resources/Textures/Objects/power_cable.rsi/cable_9.png
new file mode 100644
index 0000000000..2b988d3ffe
Binary files /dev/null and b/Resources/Textures/Objects/power_cable.rsi/cable_9.png differ
diff --git a/Resources/Textures/Objects/power_cable.rsi/meta.json b/Resources/Textures/Objects/power_cable.rsi/meta.json
new file mode 100644
index 0000000000..7e3b1a9d68
--- /dev/null
+++ b/Resources/Textures/Objects/power_cable.rsi/meta.json
@@ -0,0 +1,73 @@
+{
+ "version": 1,
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "cable_0",
+ "directions": 1
+ },
+ {
+ "name": "cable_1",
+ "directions": 1
+ },
+ {
+ "name": "cable_2",
+ "directions": 1
+ },
+ {
+ "name": "cable_3",
+ "directions": 1
+ },
+ {
+ "name": "cable_4",
+ "directions": 1
+ },
+ {
+ "name": "cable_5",
+ "directions": 1
+ },
+ {
+ "name": "cable_6",
+ "directions": 1
+ },
+ {
+ "name": "cable_7",
+ "directions": 1
+ },
+ {
+ "name": "cable_8",
+ "directions": 1
+ },
+ {
+ "name": "cable_9",
+ "directions": 1
+ },
+ {
+ "name": "cable_10",
+ "directions": 1
+ },
+ {
+ "name": "cable_11",
+ "directions": 1
+ },
+ {
+ "name": "cable_12",
+ "directions": 1
+ },
+ {
+ "name": "cable_13",
+ "directions": 1
+ },
+ {
+ "name": "cable_14",
+ "directions": 1
+ },
+ {
+ "name": "cable_15",
+ "directions": 1
+ },
+ ]
+}