Wire hacking is now fancy.

1. new UI
2. wires are correctly randomized.
3. wires layouts
are shared across machines in the same round.
This commit is contained in:
Pieter-Jan Briers
2020-05-27 15:09:22 +02:00
parent 4e1303caa3
commit 195c16d800
40 changed files with 1855 additions and 135 deletions

View File

@@ -1,17 +1,11 @@
using System;
using Robust.Client.GameObjects.Components.UserInterface; using Robust.Client.GameObjects.Components.UserInterface;
using Robust.Shared.GameObjects.Components.UserInterface; using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using static Content.Shared.GameObjects.Components.SharedWiresComponent; using static Content.Shared.GameObjects.Components.SharedWiresComponent;
namespace Content.Client.GameObjects.Components.Wires namespace Content.Client.GameObjects.Components.Wires
{ {
public class WiresBoundUserInterface : BoundUserInterface public class WiresBoundUserInterface : BoundUserInterface
{ {
#pragma warning disable 649
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649
public WiresBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) public WiresBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{ {
} }
@@ -21,7 +15,7 @@ namespace Content.Client.GameObjects.Components.Wires
protected override void Open() protected override void Open()
{ {
base.Open(); base.Open();
_menu = new WiresMenu(_localizationManager) {Owner = this}; _menu = new WiresMenu(this);
_menu.OnClose += Close; _menu.OnClose += Close;
_menu.OpenCentered(); _menu.OpenCentered();
@@ -33,9 +27,16 @@ namespace Content.Client.GameObjects.Components.Wires
_menu.Populate((WiresBoundUserInterfaceState) state); _menu.Populate((WiresBoundUserInterfaceState) state);
} }
public void PerformAction(Guid guid, WiresAction action) public void PerformAction(int id, WiresAction action)
{ {
SendMessage(new WiresActionMessage(guid, action)); SendMessage(new WiresActionMessage(id, action));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_menu.Close();
} }
} }
} }

View File

@@ -1,66 +1,618 @@
using System;
using Content.Client.Animations;
using Content.Client.GameObjects.EntitySystems;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Shared.GameObjects.Components;
using Robust.Client.Animations;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Animations;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using static Content.Shared.GameObjects.Components.SharedWiresComponent; using static Content.Shared.GameObjects.Components.SharedWiresComponent;
namespace Content.Client.GameObjects.Components.Wires namespace Content.Client.GameObjects.Components.Wires
{ {
public class WiresMenu : SS14Window public class WiresMenu : BaseWindow
{ {
private readonly ILocalizationManager _localizationManager; public WiresBoundUserInterface Owner { get; }
protected override Vector2? CustomSize => (300, 150);
public WiresBoundUserInterface Owner { get; set; }
private readonly VBoxContainer _wiresContainer; private readonly Control _wiresHBox;
private readonly Control _topContainer;
private readonly Control _statusContainer;
public WiresMenu(ILocalizationManager localizationManager) private readonly Label _nameLabel;
private readonly Label _serialLabel;
public TextureButton CloseButton { get; set; }
public WiresMenu(WiresBoundUserInterface owner)
{ {
_localizationManager = localizationManager; var resourceCache = IoCManager.Resolve<IResourceCache>();
Title = _localizationManager.GetString("Wires");
_wiresContainer = new VBoxContainer(); Owner = owner;
Contents.AddChild(_wiresContainer); var rootContainer = new LayoutContainer {Name = "WireRoot"};
AddChild(rootContainer);
MouseFilter = MouseFilterMode.Stop;
var panelTex = resourceCache.GetTexture("/Nano/button.svg.96dpi.png");
var back = new StyleBoxTexture
{
Texture = panelTex,
Modulate = Color.FromHex("#25252A"),
};
back.SetPatchMargin(StyleBox.Margin.All, 10);
var topPanel = new PanelContainer
{
PanelOverride = back,
MouseFilter = MouseFilterMode.Pass
};
var bottomWrap = new LayoutContainer
{
Name = "BottomWrap"
};
var bottomPanel = new PanelContainer
{
PanelOverride = back,
MouseFilter = MouseFilterMode.Pass
};
var shadow = new HBoxContainer
{
Children =
{
new PanelContainer
{
CustomMinimumSize = (2, 0),
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
},
new PanelContainer
{
SizeFlagsHorizontal = SizeFlags.FillExpand,
MouseFilter = MouseFilterMode.Stop,
Name = "Shadow",
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.5f)}
},
new PanelContainer
{
CustomMinimumSize = (2, 0),
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
},
} }
};
var wrappingHBox = new HBoxContainer();
_wiresHBox = new HBoxContainer {SeparationOverride = 4, SizeFlagsVertical = SizeFlags.ShrinkEnd};
wrappingHBox.AddChild(new Control {CustomMinimumSize = (20, 0)});
wrappingHBox.AddChild(_wiresHBox);
wrappingHBox.AddChild(new Control {CustomMinimumSize = (20, 0)});
bottomWrap.AddChild(bottomPanel);
LayoutContainer.SetAnchorPreset(bottomPanel, LayoutContainer.LayoutPreset.BottomWide);
LayoutContainer.SetMarginTop(bottomPanel, -55);
bottomWrap.AddChild(shadow);
LayoutContainer.SetAnchorPreset(shadow, LayoutContainer.LayoutPreset.BottomWide);
LayoutContainer.SetMarginBottom(shadow, -55);
LayoutContainer.SetMarginTop(shadow, -80);
LayoutContainer.SetMarginLeft(shadow, 12);
LayoutContainer.SetMarginRight(shadow, -12);
bottomWrap.AddChild(wrappingHBox);
LayoutContainer.SetAnchorPreset(wrappingHBox, LayoutContainer.LayoutPreset.Wide);
LayoutContainer.SetMarginBottom(wrappingHBox, -4);
rootContainer.AddChild(topPanel);
rootContainer.AddChild(bottomWrap);
LayoutContainer.SetAnchorPreset(topPanel, LayoutContainer.LayoutPreset.Wide);
LayoutContainer.SetMarginBottom(topPanel, -80);
LayoutContainer.SetAnchorPreset(bottomWrap, LayoutContainer.LayoutPreset.VerticalCenterWide);
LayoutContainer.SetGrowHorizontal(bottomWrap, LayoutContainer.GrowDirection.Both);
var topContainerWrap = new VBoxContainer
{
Children =
{
(_topContainer = new VBoxContainer()),
new Control {CustomMinimumSize = (0, 110)}
}
};
rootContainer.AddChild(topContainerWrap);
LayoutContainer.SetAnchorPreset(topContainerWrap, LayoutContainer.LayoutPreset.Wide);
var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13);
var fontSmall = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 10);
Button helpButton;
var topRow = new MarginContainer
{
MarginLeftOverride = 4,
MarginTopOverride = 2,
MarginRightOverride = 12,
MarginBottomOverride = 2,
Children =
{
new HBoxContainer
{
Children =
{
(_nameLabel = new Label
{
Text = Loc.GetString("Wires"),
FontOverride = font,
FontColorOverride = StyleNano.NanoGold,
SizeFlagsVertical = SizeFlags.ShrinkCenter
}),
new Control
{
CustomMinimumSize = (8, 0),
},
(_serialLabel = new Label
{
Text = Loc.GetString("DEAD-BEEF"),
FontOverride = fontSmall,
FontColorOverride = Color.Gray,
SizeFlagsVertical = SizeFlags.ShrinkCenter
}),
new Control
{
CustomMinimumSize = (20, 0),
SizeFlagsHorizontal = SizeFlags.Expand
},
(helpButton = new Button {Text = "?"}),
new Control
{
CustomMinimumSize = (2, 0),
},
(CloseButton = new TextureButton
{
StyleClasses = {SS14Window.StyleClassWindowCloseButton},
SizeFlagsVertical = SizeFlags.ShrinkCenter
})
}
}
}
};
helpButton.OnPressed += a =>
{
var popup = new HelpPopup();
UserInterfaceManager.ModalRoot.AddChild(popup);
popup.Open(UIBox2.FromDimensions(a.Event.PointerLocation.Position, (400, 200)));
};
var middle = new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#202025")},
Children =
{
new HBoxContainer
{
Children =
{
new MarginContainer
{
MarginLeftOverride = 8,
MarginRightOverride = 8,
MarginTopOverride = 4,
MarginBottomOverride = 4,
Children =
{
(_statusContainer = new GridContainer
{
// TODO: automatically change columns count.
Columns = 3
})
}
}
}
}
}
};
_topContainer.AddChild(topRow);
_topContainer.AddChild(new PanelContainer
{
CustomMinimumSize = (0, 2),
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
});
_topContainer.AddChild(middle);
_topContainer.AddChild(new PanelContainer
{
CustomMinimumSize = (0, 2),
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#525252ff")}
});
CloseButton.OnPressed += _ => Close();
LayoutContainer.SetSize(this, (300, 200));
}
public void Populate(WiresBoundUserInterfaceState state) public void Populate(WiresBoundUserInterfaceState state)
{ {
_wiresContainer.RemoveAllChildren(); _nameLabel.Text = state.BoardName;
_serialLabel.Text = state.SerialNumber;
_wiresHBox.RemoveAllChildren();
var random = new Random(state.WireSeed);
foreach (var wire in state.WiresList) foreach (var wire in state.WiresList)
{ {
var container = new HBoxContainer(); var mirror = random.Next(2) == 0;
var newLabel = new Label() var flip = random.Next(2) == 0;
var type = random.Next(2);
var control = new WireControl(wire.Color, wire.Letter, wire.IsCut, flip, mirror, type)
{ {
Text = $"{_localizationManager.GetString(wire.Color.Name())}: ", SizeFlagsVertical = SizeFlags.ShrinkEnd
FontColorOverride = wire.Color,
}; };
container.AddChild(newLabel); _wiresHBox.AddChild(control);
var newButton = new Button() control.WireClicked += () =>
{ {
Text = _localizationManager.GetString("Pulse"), Owner.PerformAction(wire.Id, wire.IsCut ? WiresAction.Mend : WiresAction.Cut);
}; };
newButton.OnPressed += _ => Owner.PerformAction(wire.Guid, WiresAction.Pulse);
container.AddChild(newButton);
newButton = new Button() control.ContactsClicked += () =>
{ {
Text = wire.IsCut ? _localizationManager.GetString("Mend") : _localizationManager.GetString("Cut"), Owner.PerformAction(wire.Id, WiresAction.Pulse);
}; };
newButton.OnPressed += _ => Owner.PerformAction(wire.Guid, wire.IsCut ? WiresAction.Mend : WiresAction.Cut);
container.AddChild(newButton);
_wiresContainer.AddChild(container);
} }
_statusContainer.RemoveAllChildren();
foreach (var status in state.Statuses) foreach (var status in state.Statuses)
{ {
var container = new HBoxContainer(); if (status.Value is StatusLightData statusLightData)
container.AddChild(new Label
{ {
Text = status _statusContainer.AddChild(new StatusLight(statusLightData));
}
else
{
_statusContainer.AddChild(new Label
{
Text = status.ToString()
}); });
_wiresContainer.AddChild(container); }
} }
} }
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
{
return DragMode.Move;
}
protected override bool HasPoint(Vector2 point)
{
// This makes it so our base window won't count for hit tests,
// but we will still receive mouse events coming in from Pass mouse filter mode.
// So basically, it perfectly shells out the hit tests to the panels we have!
return false;
}
private sealed class WireControl : Control
{
private const string TextureContact = "/Textures/UserInterface/WireHacking/contact.svg.96dpi.png";
public event Action WireClicked;
public event Action ContactsClicked;
public WireControl(WireColor color, WireLetter letter, bool isCut, bool flip, bool mirror, int type)
{
SizeFlagsHorizontal = SizeFlags.ShrinkCenter;
MouseFilter = MouseFilterMode.Stop;
var resourceCache = IoCManager.Resolve<IResourceCache>();
var layout = new LayoutContainer();
AddChild(layout);
var greek = new Label
{
Text = letter.Letter().ToString(),
SizeFlagsVertical = SizeFlags.ShrinkEnd,
SizeFlagsHorizontal = SizeFlags.ShrinkCenter,
Align = Label.AlignMode.Center,
FontOverride = resourceCache.GetFont("/Fonts/NotoSansDisplay/NotoSansDisplay-Bold.ttf", 12),
FontColorOverride = Color.Gray,
ToolTip = letter.Name(),
MouseFilter = MouseFilterMode.Stop
};
layout.AddChild(greek);
LayoutContainer.SetAnchorPreset(greek, LayoutContainer.LayoutPreset.BottomWide);
LayoutContainer.SetGrowVertical(greek, LayoutContainer.GrowDirection.Begin);
LayoutContainer.SetGrowHorizontal(greek, LayoutContainer.GrowDirection.Both);
var contactTexture = resourceCache.GetTexture(TextureContact);
var contact1 = new TextureRect
{
Texture = contactTexture,
Modulate = Color.FromHex("#E1CA76")
};
layout.AddChild(contact1);
LayoutContainer.SetPosition(contact1, (0, 0));
var contact2 = new TextureRect
{
Texture = contactTexture,
Modulate = Color.FromHex("#E1CA76")
};
layout.AddChild(contact2);
LayoutContainer.SetPosition(contact2, (0, 60));
var wire = new WireRender(color, isCut, flip, mirror, type);
layout.AddChild(wire);
LayoutContainer.SetPosition(wire, (2, 16));
ToolTip = color.Name();
}
protected override Vector2 CalculateMinimumSize()
{
return (20, 102);
}
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
base.KeyBindDown(args);
if (args.Function != EngineKeyFunctions.UIClick)
{
return;
}
if (args.RelativePixelPosition.Y > 20 && args.RelativePixelPosition.Y < 60)
{
WireClicked?.Invoke();
}
else
{
ContactsClicked?.Invoke();
}
}
protected override bool HasPoint(Vector2 point)
{
return base.HasPoint(point) && point.Y <= 80;
}
private sealed class WireRender : Control
{
private readonly WireColor _color;
private readonly bool _isCut;
private readonly bool _flip;
private readonly bool _mirror;
private readonly int _type;
private static readonly string[] TextureNormal =
{
"/Textures/UserInterface/WireHacking/wire_1.svg.96dpi.png",
"/Textures/UserInterface/WireHacking/wire_2.svg.96dpi.png"
};
private static readonly string[] TextureCut =
{
"/Textures/UserInterface/WireHacking/wire_1_cut.svg.96dpi.png",
"/Textures/UserInterface/WireHacking/wire_2_cut.svg.96dpi.png",
};
private static readonly string[] TextureCopper =
{
"/Textures/UserInterface/WireHacking/wire_1_copper.svg.96dpi.png",
"/Textures/UserInterface/WireHacking/wire_2_copper.svg.96dpi.png"
};
public WireRender(WireColor color, bool isCut, bool flip, bool mirror, int type)
{
_color = color;
_isCut = isCut;
_flip = flip;
_mirror = mirror;
_type = type;
}
protected override Vector2 CalculateMinimumSize()
{
return (16, 50);
}
protected override void Draw(DrawingHandleScreen handle)
{
var resC = IoCManager.Resolve<IResourceCache>();
var colorValue = _color.ColorValue();
var tex = resC.GetTexture(_isCut ? TextureCut[_type] : TextureNormal[_type]);
var l = 0f;
var r = tex.Width + l;
var t = 0f;
var b = tex.Height + t;
if (_flip)
{
(t, b) = (b, t);
}
if (_mirror)
{
(l, r) = (r, l);
}
l *= UIScale;
r *= UIScale;
t *= UIScale;
b *= UIScale;
var rect = new UIBox2(l, t, r, b);
if (_isCut)
{
var copper = Color.Orange;
var copperTex = resC.GetTexture(TextureCopper[_type]);
handle.DrawTextureRect(copperTex, rect, copper);
}
handle.DrawTextureRect(tex, rect, colorValue);
}
}
}
private sealed class StatusLight : Control
{
private static readonly Animation _blinkingFast = new Animation
{
Length = TimeSpan.FromSeconds(0.2),
AnimationTracks =
{
new AnimationTrackControlProperty
{
Property = nameof(Control.Modulate),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Color.White, 0f),
new AnimationTrackProperty.KeyFrame(Color.Transparent, 0.1f),
new AnimationTrackProperty.KeyFrame(Color.White, 0.1f)
}
}
}
};
private static readonly Animation _blinkingSlow = new Animation
{
Length = TimeSpan.FromSeconds(0.8),
AnimationTracks =
{
new AnimationTrackControlProperty
{
Property = nameof(Control.Modulate),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(Color.White, 0f),
new AnimationTrackProperty.KeyFrame(Color.White, 0.3f),
new AnimationTrackProperty.KeyFrame(Color.Transparent, 0.1f),
new AnimationTrackProperty.KeyFrame(Color.Transparent, 0.3f),
new AnimationTrackProperty.KeyFrame(Color.White, 0.1f),
}
}
}
};
public StatusLight(StatusLightData data)
{
var resC = IoCManager.Resolve<IResourceCache>();
var hsv = Color.ToHsv(data.Color);
hsv.Z /= 2;
var dimColor = Color.FromHsv(hsv);
TextureRect activeLight;
var lightContainer = new Control
{
Children =
{
new TextureRect
{
Texture = resC.GetTexture(
"/Textures/UserInterface/WireHacking/light_off_base.svg.96dpi.png"),
Stretch = TextureRect.StretchMode.KeepCentered,
ModulateSelfOverride = dimColor
},
(activeLight = new TextureRect
{
ModulateSelfOverride = data.Color.WithAlpha(0.4f),
Stretch = TextureRect.StretchMode.KeepCentered,
Texture =
resC.GetTexture("/Textures/UserInterface/WireHacking/light_on_base.svg.96dpi.png"),
})
}
};
Animation animation = null;
switch (data.State)
{
case StatusLightState.Off:
activeLight.Visible = false;
break;
case StatusLightState.On:
break;
case StatusLightState.BlinkingFast:
animation = _blinkingFast;
break;
case StatusLightState.BlinkingSlow:
animation = _blinkingSlow;
break;
default:
throw new ArgumentOutOfRangeException();
}
if (animation != null)
{
activeLight.PlayAnimation(animation, "blink");
activeLight.AnimationCompleted += s =>
{
if (s == "blink")
{
activeLight.PlayAnimation(animation, s);
}
};
}
var font = IoCManager.Resolve<IResourceCache>().GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 12);
var hBox = new HBoxContainer {SeparationOverride = 4};
hBox.AddChild(new Label
{
Text = data.Text,
FontOverride = font,
FontColorOverride = Color.FromHex("#A1A6AE"),
SizeFlagsVertical = SizeFlags.ShrinkCenter,
});
hBox.AddChild(lightContainer);
hBox.AddChild(new Control {CustomMinimumSize = (6, 0)});
AddChild(hBox);
}
}
private sealed class HelpPopup : Popup
{
private const string Text = "Click on the gold contacts with a multitool in hand to pulse their wire.\n" +
"Click on the wires with a pair of wirecutters in hand to cut/mend them.\n\n" +
"The lights at the top show the state of the machine, " +
"messing with wires will probably do stuff to them.\n" +
"Wire layouts are different each round, " +
"but consistent between machines of the same type.";
public HelpPopup()
{
var label = new RichTextLabel();
label.SetMessage(Text);
AddChild(new PanelContainer
{
StyleClasses = {ExamineSystem.StyleClassEntityTooltip},
Children = {label}
});
}
}
} }
} }

View File

@@ -5,7 +5,6 @@ using Content.Server.GameObjects.Components.Power;
using Content.Server.GameObjects.Components.VendingMachines; using Content.Server.GameObjects.Components.VendingMachines;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Server.Utility;
using Content.Shared.GameObjects.Components.Doors; using Content.Shared.GameObjects.Components.Doors;
using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.Interactable;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
@@ -13,6 +12,8 @@ using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Maths;
using static Content.Shared.GameObjects.Components.SharedWiresComponent;
using static Content.Shared.GameObjects.Components.SharedWiresComponent.WiresAction; using static Content.Shared.GameObjects.Components.SharedWiresComponent.WiresAction;
using Timer = Robust.Shared.Timers.Timer; using Timer = Robust.Shared.Timers.Timer;
@@ -40,6 +41,7 @@ namespace Content.Server.GameObjects.Components.Doors
private CancellationTokenSource _powerWiresPulsedTimerCancel; private CancellationTokenSource _powerWiresPulsedTimerCancel;
private bool _powerWiresPulsed; private bool _powerWiresPulsed;
/// <summary> /// <summary>
/// True if either power wire was pulsed in the last <see cref="PowerWiresTimeout"/>. /// True if either power wire was pulsed in the last <see cref="PowerWiresTimeout"/>.
/// </summary> /// </summary>
@@ -56,16 +58,30 @@ namespace Content.Server.GameObjects.Components.Doors
private void UpdateWiresStatus() private void UpdateWiresStatus()
{ {
var powerMessage = "A yellow light is on."; var powerLight = new StatusLightData(Color.Yellow, StatusLightState.On, "POWR");
if (PowerWiresPulsed) if (PowerWiresPulsed)
{ {
powerMessage = "A yellow light is blinking rapidly."; powerLight = new StatusLightData(Color.Yellow, StatusLightState.BlinkingFast, "POWR");
} else if (_wires.IsWireCut(Wires.MainPower) && }
else if (_wires.IsWireCut(Wires.MainPower) &&
_wires.IsWireCut(Wires.BackupPower)) _wires.IsWireCut(Wires.BackupPower))
{ {
powerMessage = "A red light is on."; powerLight = new StatusLightData(Color.Red, StatusLightState.On, "POWR");
} }
_wires.SetStatus(WiresStatus.PowerIndicator, _localizationMgr.GetString(powerMessage));
_wires.SetStatus(AirlockWireStatus.PowerIndicator, powerLight);
_wires.SetStatus(1, new StatusLightData(Color.Red, StatusLightState.Off, "BOLT"));
_wires.SetStatus(2, new StatusLightData(Color.Lime, StatusLightState.On, "BLTL"));
_wires.SetStatus(3, new StatusLightData(Color.Purple, StatusLightState.BlinkingSlow, "AICT"));
_wires.SetStatus(4, new StatusLightData(Color.Orange, StatusLightState.Off, "TIME"));
_wires.SetStatus(5, new StatusLightData(Color.Red, StatusLightState.Off, "SAFE"));
/*
_wires.SetStatus(6, powerLight);
_wires.SetStatus(7, powerLight);
_wires.SetStatus(8, powerLight);
_wires.SetStatus(9, powerLight);
_wires.SetStatus(10, powerLight);
_wires.SetStatus(11, powerLight);*/
} }
private void UpdatePowerCutStatus() private void UpdatePowerCutStatus()
@@ -125,19 +141,26 @@ namespace Content.Server.GameObjects.Components.Doors
/// Mending restores power. /// Mending restores power.
/// </summary> /// </summary>
MainPower, MainPower,
/// <see cref="MainPower"/> /// <see cref="MainPower"/>
BackupPower, BackupPower,
} }
private enum WiresStatus
{
PowerIndicator,
}
public void RegisterWires(WiresComponent.WiresBuilder builder) public void RegisterWires(WiresComponent.WiresBuilder builder)
{ {
builder.CreateWire(Wires.MainPower); builder.CreateWire(Wires.MainPower);
builder.CreateWire(Wires.BackupPower); builder.CreateWire(Wires.BackupPower);
builder.CreateWire(1);
builder.CreateWire(2);
builder.CreateWire(3);
builder.CreateWire(4);
/*builder.CreateWire(5);
builder.CreateWire(6);
builder.CreateWire(7);
builder.CreateWire(8);
builder.CreateWire(9);
builder.CreateWire(10);
builder.CreateWire(11);*/
UpdateWiresStatus(); UpdateWiresStatus();
} }
@@ -192,6 +215,7 @@ namespace Content.Server.GameObjects.Components.Doors
{ {
return; return;
} }
base.Deny(); base.Deny();
} }
@@ -216,11 +240,10 @@ namespace Content.Server.GameObjects.Components.Doors
if (State == DoorState.Closed) if (State == DoorState.Closed)
Open(); Open();
else if(State == DoorState.Open) else if (State == DoorState.Open)
Close(); Close();
return true; return true;
} }
} }
} }

View File

@@ -6,43 +6,43 @@ using Content.Server.GameObjects.Components.VendingMachines;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Server.Interfaces.GameObjects; using Content.Server.Interfaces.GameObjects;
using Content.Server.Utility;
using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Interactable; using Content.Shared.GameObjects.Components.Interactable;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.GameObjects.EntitySystems; using Robust.Server.GameObjects.EntitySystems;
using Robust.Server.Interfaces.GameObjects;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems; using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Random; using Robust.Shared.Interfaces.Random;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Random; using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.Utility; using Robust.Shared.Utility;
using Robust.Shared.Utility; using Robust.Shared.ViewVariables;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components
{ {
[RegisterComponent] [RegisterComponent]
public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IRobustRandom _random; [Dependency] private readonly IRobustRandom _random;
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly IServerNotifyManager _notifyManager;
[Dependency] private readonly ILocalizationManager _localizationManager;
#pragma warning restore 649 #pragma warning restore 649
private AudioSystem _audioSystem; private AudioSystem _audioSystem;
private AppearanceComponent _appearance; private AppearanceComponent _appearance;
private BoundUserInterface _userInterface; private BoundUserInterface _userInterface;
private bool _isPanelOpen; private bool _isPanelOpen;
/// <summary> /// <summary>
/// Opening the maintenance panel (typically with a screwdriver) changes this. /// Opening the maintenance panel (typically with a screwdriver) changes this.
/// </summary> /// </summary>
[ViewVariables]
public bool IsPanelOpen public bool IsPanelOpen
{ {
get => _isPanelOpen; get => _isPanelOpen;
@@ -52,15 +52,18 @@ namespace Content.Server.GameObjects.Components
{ {
return; return;
} }
_isPanelOpen = value; _isPanelOpen = value;
UpdateAppearance(); UpdateAppearance();
} }
} }
private bool _isPanelVisible = true; private bool _isPanelVisible = true;
/// <summary> /// <summary>
/// Components can set this to prevent the maintenance panel overlay from showing even if it's open /// Components can set this to prevent the maintenance panel overlay from showing even if it's open
/// </summary> /// </summary>
[ViewVariables]
public bool IsPanelVisible public bool IsPanelVisible
{ {
get => _isPanelVisible; get => _isPanelVisible;
@@ -70,11 +73,34 @@ namespace Content.Server.GameObjects.Components
{ {
return; return;
} }
_isPanelVisible = value; _isPanelVisible = value;
UpdateAppearance(); UpdateAppearance();
} }
} }
[ViewVariables(VVAccess.ReadWrite)]
public string BoardName
{
get => _boardName;
set
{
_boardName = value;
UpdateUserInterface();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public string SerialNumber
{
get => _serialNumber;
set
{
_serialNumber = value;
UpdateUserInterface();
}
}
private void UpdateAppearance() private void UpdateAppearance()
{ {
_appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen && IsPanelVisible); _appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen && IsPanelVisible);
@@ -88,26 +114,27 @@ namespace Content.Server.GameObjects.Components
/// <summary> /// <summary>
/// Status messages are displayed at the bottom of the UI. /// Status messages are displayed at the bottom of the UI.
/// </summary> /// </summary>
private readonly Dictionary<object, string> _statuses = new Dictionary<object, string>(); private readonly Dictionary<object, object> _statuses = new Dictionary<object, object>();
/// <summary> /// <summary>
/// <see cref="AssignColor"/> and <see cref="WiresBuilder.CreateWire"/>. /// <see cref="AssignAppearance"/> and <see cref="WiresBuilder.CreateWire"/>.
/// </summary> /// </summary>
private readonly List<Color> _availableColors = new List<Color>() private readonly List<WireColor> _availableColors =
{ new List<WireColor>((WireColor[]) Enum.GetValues(typeof(WireColor)));
Color.Red,
Color.Blue, private readonly List<WireLetter> _availableLetters =
Color.Green, new List<WireLetter>((WireLetter[]) Enum.GetValues(typeof(WireLetter)));
Color.Orange,
Color.Brown, private string _boardName;
Color.Gold,
Color.Gray, private string _serialNumber;
Color.Cyan,
Color.Navy, // Used to generate wire appearance randomization client side.
Color.Purple, // We honestly don't care what it is or such but do care that it doesn't change between UI re-opens.
Color.Pink, [ViewVariables]
Color.Fuchsia, private int _wireSeed;
}; [ViewVariables]
private string _layoutId;
public override void Initialize() public override void Initialize()
{ {
@@ -120,16 +147,89 @@ namespace Content.Server.GameObjects.Components
_userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; _userInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
} }
private void GenerateSerialNumber()
{
var random = IoCManager.Resolve<IRobustRandom>();
Span<char> data = stackalloc char[9];
data[4] = '-';
if (random.Prob(0.01f))
{
for (var i = 0; i < 4; i++)
{
// Cyrillic Letters
data[i] = (char) random.Next(0x0410, 0x0430);
}
}
else
{
for (var i = 0; i < 4; i++)
{
// Letters
data[i] = (char) random.Next(0x41, 0x5B);
}
}
for (var i = 5; i < 9; i++)
{
// Digits
data[i] = (char) random.Next(0x30, 0x3A);
}
SerialNumber = new string(data);
}
protected override void Startup() protected override void Startup()
{ {
base.Startup(); base.Startup();
WireLayout layout = null;
var hackingSystem = EntitySystem.Get<WireHackingSystem>();
if (_layoutId != null)
{
hackingSystem.TryGetLayout(_layoutId, out layout);
}
foreach (var wiresProvider in Owner.GetAllComponents<IWires>()) foreach (var wiresProvider in Owner.GetAllComponents<IWires>())
{ {
var builder = new WiresBuilder(this, wiresProvider); var builder = new WiresBuilder(this, wiresProvider, layout);
wiresProvider.RegisterWires(builder); wiresProvider.RegisterWires(builder);
} }
if (layout != null)
{
WiresList.Sort((a, b) =>
{
var pA = layout.Specifications[a.Identifier].Position;
var pB = layout.Specifications[b.Identifier].Position;
return pA.CompareTo(pB);
});
}
else
{
IoCManager.Resolve<IRobustRandom>().Shuffle(WiresList);
if (_layoutId != null)
{
var dict = new Dictionary<object, WireLayout.WireData>();
for (var i = 0; i < WiresList.Count; i++)
{
var d = WiresList[i];
dict.Add(d.Identifier, new WireLayout.WireData(d.Letter, d.Color, i));
}
hackingSystem.AddLayout(_layoutId, new WireLayout(dict));
}
}
var id = 0;
foreach (var wire in WiresList)
{
wire.Id = ++id;
}
UpdateUserInterface(); UpdateUserInterface();
} }
@@ -140,39 +240,53 @@ namespace Content.Server.GameObjects.Components
public bool IsWireCut(object identifier) public bool IsWireCut(object identifier)
{ {
var wire = WiresList.Find(x => x.Identifier.Equals(identifier)); var wire = WiresList.Find(x => x.Identifier.Equals(identifier));
if(wire == null) throw new ArgumentException(); if (wire == null) throw new ArgumentException();
return wire.IsCut; return wire.IsCut;
} }
public class Wire public class Wire
{ {
/// <summary>
/// Used in client-server communication to identify a wire without telling the client what the wire does.
/// </summary>
public readonly Guid Guid;
/// <summary>
/// Registered by components implementing IWires, used to identify which wire the client interacted with.
/// </summary>
public readonly object Identifier;
/// <summary>
/// The color of the wire. It needs to have a corresponding entry in <see cref="Robust.Shared.Maths.Color.DefaultColors"/>.
/// </summary>
public readonly Color Color;
/// <summary> /// <summary>
/// The component that registered the wire. /// The component that registered the wire.
/// </summary> /// </summary>
public readonly IWires Owner; public IWires Owner { get; }
/// <summary> /// <summary>
/// Whether the wire is cut. /// Whether the wire is cut.
/// </summary> /// </summary>
public bool IsCut; public bool IsCut { get; set; }
public Wire(Guid guid, object identifier, Color color, IWires owner, bool isCut)
/// <summary>
/// Used in client-server communication to identify a wire without telling the client what the wire does.
/// </summary>
[ViewVariables]
public int Id { get; set; }
/// <summary>
/// The color of the wire.
/// </summary>
[ViewVariables]
public WireColor Color { get; }
/// <summary>
/// The greek letter shown below the wire.
/// </summary>
[ViewVariables]
public WireLetter Letter { get; }
/// <summary>
/// Registered by components implementing IWires, used to identify which wire the client interacted with.
/// </summary>
[ViewVariables]
public object Identifier { get; }
public Wire(IWires owner, bool isCut, WireColor color, WireLetter letter, object identifier)
{ {
Guid = guid;
Identifier = identifier;
Color = color;
Owner = owner; Owner = owner;
IsCut = isCut; IsCut = isCut;
Color = color;
Letter = letter;
Identifier = identifier;
} }
} }
@@ -183,24 +297,42 @@ namespace Content.Server.GameObjects.Components
{ {
[NotNull] private readonly WiresComponent _wires; [NotNull] private readonly WiresComponent _wires;
[NotNull] private readonly IWires _owner; [NotNull] private readonly IWires _owner;
[CanBeNull] private readonly WireLayout _layout;
public WiresBuilder(WiresComponent wires, IWires owner) public WiresBuilder(WiresComponent wires, IWires owner, WireLayout layout)
{ {
_wires = wires; _wires = wires;
_owner = owner; _owner = owner;
_layout = layout;
} }
public void CreateWire(object identifier, Color? color = null, bool isCut = false) public void CreateWire(object identifier, (WireColor, WireLetter)? appearance = null, bool isCut = false)
{ {
if (!color.HasValue) WireLetter letter;
WireColor color;
if (!appearance.HasValue)
{ {
color = _wires.AssignColor(); if (_layout != null && _layout.Specifications.TryGetValue(identifier, out var specification))
{
color = specification.Color;
letter = specification.Letter;
_wires._availableColors.Remove(color);
_wires._availableLetters.Remove(letter);
} }
else else
{ {
_wires._availableColors.Remove(color.Value); (color, letter) = _wires.AssignAppearance();
} }
_wires.WiresList.Add(new Wire(Guid.NewGuid(), identifier, color.Value, _owner, isCut)); }
else
{
(color, letter) = appearance.Value;
_wires._availableColors.Remove(color);
_wires._availableLetters.Remove(letter);
}
// TODO: ENSURE NO RANDOM OVERLAP.
_wires.WiresList.Add(new Wire(_owner, isCut, color, letter, identifier));
} }
} }
@@ -208,13 +340,12 @@ namespace Content.Server.GameObjects.Components
/// Picks a color from <see cref="_availableColors"/> and removes it from the list. /// Picks a color from <see cref="_availableColors"/> and removes it from the list.
/// </summary> /// </summary>
/// <returns>The picked color.</returns> /// <returns>The picked color.</returns>
private Color AssignColor() private (WireColor, WireLetter) AssignAppearance()
{ {
if(_availableColors.Count == 0) var color = _availableColors.Count == 0 ? WireColor.Red : _random.PickAndTake(_availableColors);
{ var letter = _availableLetters.Count == 0 ? WireLetter.α : _random.PickAndTake(_availableLetters);
return Color.Black;
} return (color, letter);
return _random.PickAndTake(_availableColors);
} }
/// <summary> /// <summary>
@@ -231,30 +362,41 @@ namespace Content.Server.GameObjects.Components
switch (message) switch (message)
{ {
case WiresActionMessage msg: case WiresActionMessage msg:
var wire = WiresList.Find(x => x.Guid == msg.Guid); var wire = WiresList.Find(x => x.Id == msg.Id);
if (wire == null)
{
return;
}
var player = serverMsg.Session.AttachedEntity; var player = serverMsg.Session.AttachedEntity;
if (!player.TryGetComponent(out IHandsComponent handsComponent)) if (!player.TryGetComponent(out IHandsComponent handsComponent))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You have no hands.")); _notifyManager.PopupMessage(Owner.Transform.GridPosition, player,
Loc.GetString("You have no hands."));
return; return;
} }
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(player.Transform.MapPosition, Owner.Transform.MapPosition, ignoredEnt: Owner)) if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(player.Transform.MapPosition, Owner.Transform.MapPosition, ignoredEnt: Owner))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You can't reach there!")); _notifyManager.PopupMessage(Owner.Transform.GridPosition, player,
Loc.GetString("You can't reach there!"));
return; return;
} }
var activeHandEntity = handsComponent.GetActiveHand?.Owner; var activeHandEntity = handsComponent.GetActiveHand?.Owner;
activeHandEntity.TryGetComponent<ToolComponent>(out var tool); ToolComponent tool = null;
activeHandEntity?.TryGetComponent(out tool);
switch (msg.Action) switch (msg.Action)
{ {
case WiresAction.Cut: case WiresAction.Cut:
if (tool == null || !tool.HasQuality(ToolQuality.Cutting)) if (tool == null || !tool.HasQuality(ToolQuality.Cutting))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You need to hold a wirecutter in your hand!")); _notifyManager.PopupMessageCursor(player,
Loc.GetString("You need to hold a wirecutter in your hand!"));
return; return;
} }
tool.PlayUseSound(); tool.PlayUseSound();
wire.IsCut = true; wire.IsCut = true;
UpdateUserInterface(); UpdateUserInterface();
@@ -262,9 +404,11 @@ namespace Content.Server.GameObjects.Components
case WiresAction.Mend: case WiresAction.Mend:
if (tool == null || !tool.HasQuality(ToolQuality.Cutting)) if (tool == null || !tool.HasQuality(ToolQuality.Cutting))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You need to hold a wirecutter in your hand!")); _notifyManager.PopupMessageCursor(player,
Loc.GetString("You need to hold a wirecutter in your hand!"));
return; return;
} }
tool.PlayUseSound(); tool.PlayUseSound();
wire.IsCut = false; wire.IsCut = false;
UpdateUserInterface(); UpdateUserInterface();
@@ -272,17 +416,22 @@ namespace Content.Server.GameObjects.Components
case WiresAction.Pulse: case WiresAction.Pulse:
if (tool == null || !tool.HasQuality(ToolQuality.Multitool)) if (tool == null || !tool.HasQuality(ToolQuality.Multitool))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You need to hold a multitool in your hand!")); _notifyManager.PopupMessageCursor(player,
Loc.GetString("You need to hold a multitool in your hand!"));
return; return;
} }
if (wire.IsCut) if (wire.IsCut)
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _localizationManager.GetString("You can't pulse a wire that's been cut!")); _notifyManager.PopupMessageCursor(player,
Loc.GetString("You can't pulse a wire that's been cut!"));
return; return;
} }
_audioSystem.Play("/Audio/effects/multitool_pulse.ogg", Owner); _audioSystem.Play("/Audio/effects/multitool_pulse.ogg", Owner);
break; break;
} }
wire.Owner.WiresUpdate(new WiresUpdateEventArgs(wire.Identifier, msg.Action)); wire.Owner.WiresUpdate(new WiresUpdateEventArgs(wire.Identifier, msg.Action));
break; break;
} }
@@ -293,9 +442,27 @@ namespace Content.Server.GameObjects.Components
var clientList = new List<ClientWire>(); var clientList = new List<ClientWire>();
foreach (var entry in WiresList) foreach (var entry in WiresList)
{ {
clientList.Add(new ClientWire(entry.Guid, entry.Color, entry.IsCut)); clientList.Add(new ClientWire(entry.Id, entry.IsCut, entry.Color,
entry.Letter));
} }
_userInterface.SetState(new WiresBoundUserInterfaceState(clientList, _statuses.Values.ToList()));
_userInterface.SetState(
new WiresBoundUserInterfaceState(
clientList.ToArray(),
_statuses.Select(p => new StatusEntry(p.Key, p.Value)).ToArray(),
BoardName,
SerialNumber,
_wireSeed));
}
public override void ExposeData(ObjectSerializer serializer)
{
base.ExposeData(serializer);
serializer.DataField(ref _boardName, "BoardName", "Wires");
serializer.DataField(ref _serialNumber, "SerialNumber", null);
serializer.DataField(ref _wireSeed, "WireSeed", 0);
serializer.DataField(ref _layoutId, "LayoutId", null);
} }
bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) bool IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
@@ -307,7 +474,8 @@ namespace Content.Server.GameObjects.Components
IsPanelOpen = !IsPanelOpen; IsPanelOpen = !IsPanelOpen;
EntitySystem.Get<AudioSystem>() EntitySystem.Get<AudioSystem>()
.Play(IsPanelOpen ? "/Audio/machines/screwdriveropen.ogg" : "/Audio/machines/screwdriverclose.ogg", Owner); .Play(IsPanelOpen ? "/Audio/machines/screwdriveropen.ogg" : "/Audio/machines/screwdriverclose.ogg",
Owner);
return true; return true;
} }
@@ -320,17 +488,32 @@ namespace Content.Server.GameObjects.Components
: "The [color=lightgray]maintenance panel[/color] is [color=darkred]closed[/color].")); : "The [color=lightgray]maintenance panel[/color] is [color=darkred]closed[/color]."));
} }
public void SetStatus(object statusIdentifier, string newMessage) public void SetStatus(object statusIdentifier, object status)
{ {
if (_statuses.TryGetValue(statusIdentifier, out var storedMessage)) if (_statuses.TryGetValue(statusIdentifier, out var storedMessage))
{ {
if (storedMessage == newMessage) if (storedMessage == status)
{ {
return; return;
} }
} }
_statuses[statusIdentifier] = newMessage;
_statuses[statusIdentifier] = status;
UpdateUserInterface();
}
void IMapInit.MapInit()
{
if (SerialNumber == null)
{
GenerateSerialNumber();
}
if (_wireSeed == 0)
{
_wireSeed = IoCManager.Resolve<IRobustRandom>().Next(1, int.MaxValue);
UpdateUserInterface(); UpdateUserInterface();
} }
} }
}
} }

View File

@@ -0,0 +1,52 @@
using System.Collections.Generic;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.ViewVariables;
using static Content.Shared.GameObjects.Components.SharedWiresComponent;
namespace Content.Server.GameObjects.EntitySystems
{
public class WireHackingSystem : EntitySystem
{
[ViewVariables] private readonly Dictionary<string, WireLayout> _layouts =
new Dictionary<string, WireLayout>();
public bool TryGetLayout(string id, out WireLayout layout)
{
return _layouts.TryGetValue(id, out layout);
}
public void AddLayout(string id, WireLayout layout)
{
_layouts.Add(id, layout);
}
public void ResetLayouts()
{
_layouts.Clear();
}
}
public sealed class WireLayout
{
[ViewVariables] public IReadOnlyDictionary<object, WireData> Specifications { get; }
public WireLayout(IReadOnlyDictionary<object, WireData> specifications)
{
Specifications = specifications;
}
public sealed class WireData
{
public WireLetter Letter { get; }
public WireColor Color { get; }
public int Position { get; }
public WireData(WireLetter letter, WireColor color, int position)
{
Letter = letter;
Color = color;
Position = position;
}
}
}
}

View File

@@ -7,6 +7,7 @@ using Content.Server.GameObjects.Components.Access;
using Content.Server.GameObjects.Components.Markers; using Content.Server.GameObjects.Components.Markers;
using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Mobs;
using Content.Server.GameObjects.Components.Observer; using Content.Server.GameObjects.Components.Observer;
using Content.Server.GameObjects.EntitySystems;
using Content.Server.GameTicking.GamePresets; using Content.Server.GameTicking.GamePresets;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.Chat;
@@ -26,6 +27,7 @@ using Robust.Server.ServerStatus;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Map;
@@ -469,6 +471,8 @@ namespace Content.Server.GameTicking
_spawnedPositions.Clear(); _spawnedPositions.Clear();
_manifest.Clear(); _manifest.Clear();
EntitySystem.Get<WireHackingSystem>().ResetLayouts();
} }
private void _preRoundSetup() private void _preRoundSetup()

View File

@@ -0,0 +1,11 @@
using System;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.Components.Doors
{
[Serializable, NetSerializable]
public enum AirlockWireStatus
{
PowerIndicator,
}
}

View File

@@ -1,9 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components.UserInterface; using Robust.Shared.GameObjects.Components.UserInterface;
using Robust.Shared.Localization;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using static Content.Shared.GameObjects.Components.SharedWiresComponent;
namespace Content.Shared.GameObjects.Components namespace Content.Shared.GameObjects.Components
{ {
@@ -31,44 +34,257 @@ namespace Content.Shared.GameObjects.Components
Pulse, Pulse,
} }
[Serializable, NetSerializable]
public enum StatusLightState
{
Off,
On,
BlinkingFast,
BlinkingSlow
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
[PublicAPI]
[Serializable, NetSerializable]
public enum WireLetter : byte
{
α,
β,
γ,
δ,
ε,
ζ,
η,
θ,
ι,
κ,
λ,
μ,
ν,
ξ,
ο,
π,
ρ,
σ,
τ,
υ,
φ,
χ,
ψ,
ω
}
[PublicAPI]
[Serializable, NetSerializable]
public enum WireColor : byte
{
Red,
Blue,
Green,
Orange,
Brown,
Gold,
Gray,
Cyan,
Navy,
Purple,
Pink,
Fuchsia
}
[Serializable, NetSerializable]
public struct StatusLightData
{
public StatusLightData(Color color, StatusLightState state, string text)
{
Color = color;
State = state;
Text = text;
}
public Color Color { get; }
public StatusLightState State { get; }
public string Text { get; }
public override string ToString()
{
return $"Color: {Color}, State: {State}, Text: {Text}";
}
}
[Serializable, NetSerializable] [Serializable, NetSerializable]
public class WiresBoundUserInterfaceState : BoundUserInterfaceState public class WiresBoundUserInterfaceState : BoundUserInterfaceState
{ {
public readonly List<ClientWire> WiresList; public string BoardName { get; }
public readonly List<string> Statuses; public string SerialNumber { get; }
public ClientWire[] WiresList { get; }
public StatusEntry[] Statuses { get; }
public int WireSeed { get; }
public WiresBoundUserInterfaceState(List<ClientWire> wiresList, List<string> statuses) public WiresBoundUserInterfaceState(ClientWire[] wiresList, StatusEntry[] statuses, string boardName, string serialNumber, int wireSeed)
{ {
BoardName = boardName;
SerialNumber = serialNumber;
WireSeed = wireSeed;
WiresList = wiresList; WiresList = wiresList;
Statuses = statuses; Statuses = statuses;
} }
} }
[Serializable, NetSerializable]
public struct StatusEntry
{
public readonly object Key;
public readonly object Value;
public StatusEntry(object key, object value)
{
Key = key;
Value = value;
}
public override string ToString()
{
return $"{Key}, {Value}";
}
}
[Serializable, NetSerializable] [Serializable, NetSerializable]
public class ClientWire public class ClientWire
{ {
public Guid Guid; public int Id;
public Color Color;
public bool IsCut; public bool IsCut;
public WireColor Color;
public WireLetter Letter;
public ClientWire(Guid guid, Color color, bool isCut) public ClientWire(int id, bool isCut, WireColor color, WireLetter letter)
{ {
Guid = guid; Id = id;
Color = color;
IsCut = isCut; IsCut = isCut;
Letter = letter;
Color = color;
} }
} }
[Serializable, NetSerializable] [Serializable, NetSerializable]
public class WiresActionMessage : BoundUserInterfaceMessage public class WiresActionMessage : BoundUserInterfaceMessage
{ {
public readonly Guid Guid; public readonly int Id;
public readonly WiresAction Action; public readonly WiresAction Action;
public WiresActionMessage(Guid guid, WiresAction action)
public WiresActionMessage(int id, WiresAction action)
{ {
Guid = guid; Id = id;
Action = action; Action = action;
} }
} }
} }
public static class HackingWiresExt
{
public static string Name(this WireColor color)
{
return Loc.GetString(color switch
{
WireColor.Red => "Red",
WireColor.Blue => "Blue",
WireColor.Green => "Green",
WireColor.Orange => "Orange",
WireColor.Brown => "Brown",
WireColor.Gold => "Gold",
WireColor.Gray => "Gray",
WireColor.Cyan => "Cyan",
WireColor.Navy => "Navy",
WireColor.Purple => "Purple",
WireColor.Pink => "Pink",
WireColor.Fuchsia => "Fuchsia",
_ => throw new InvalidOperationException()
});
}
public static Color ColorValue(this WireColor color)
{
return color switch
{
WireColor.Red => Color.Red,
WireColor.Blue => Color.Blue,
WireColor.Green => Color.Green,
WireColor.Orange => Color.Orange,
WireColor.Brown => Color.Brown,
WireColor.Gold => Color.Gold,
WireColor.Gray => Color.Gray,
WireColor.Cyan => Color.Cyan,
WireColor.Navy => Color.Navy,
WireColor.Purple => Color.Purple,
WireColor.Pink => Color.Pink,
WireColor.Fuchsia => Color.Fuchsia,
_ => throw new InvalidOperationException()
};
}
public static string Name(this WireLetter letter)
{
return Loc.GetString(letter switch
{
WireLetter.α => "Alpha",
WireLetter.β => "Beta",
WireLetter.γ => "Gamma",
WireLetter.δ => "Delta",
WireLetter.ε => "Epsilon",
WireLetter.ζ => "Zeta",
WireLetter.η => "Eta",
WireLetter.θ => "Theta",
WireLetter.ι => "Iota",
WireLetter.κ => "Kappa",
WireLetter.λ => "Lambda",
WireLetter.μ => "Mu",
WireLetter.ν => "Nu",
WireLetter.ξ => "Xi",
WireLetter.ο => "Omicron",
WireLetter.π => "Pi",
WireLetter.ρ => "Rho",
WireLetter.σ => "Sigma",
WireLetter.τ => "Tau",
WireLetter.υ => "Upsilon",
WireLetter.φ => "Phi",
WireLetter.χ => "Chi",
WireLetter.ψ => "Psi",
WireLetter.ω => "Omega",
_ => throw new InvalidOperationException()
});
}
public static char Letter(this WireLetter letter)
{
return letter switch
{
WireLetter.α => 'α',
WireLetter.β => 'β',
WireLetter.γ => 'γ',
WireLetter.δ => 'δ',
WireLetter.ε => 'ε',
WireLetter.ζ => 'ζ',
WireLetter.η => 'η',
WireLetter.θ => 'θ',
WireLetter.ι => 'ι',
WireLetter.κ => 'κ',
WireLetter.λ => 'λ',
WireLetter.μ => 'μ',
WireLetter.ν => 'ν',
WireLetter.ξ => 'ξ',
WireLetter.ο => 'ο',
WireLetter.π => 'π',
WireLetter.ρ => 'ρ',
WireLetter.σ => 'σ',
WireLetter.τ => 'τ',
WireLetter.υ => 'υ',
WireLetter.φ => 'φ',
WireLetter.χ => 'χ',
WireLetter.ψ => 'ψ',
WireLetter.ω => 'ω',
_ => throw new InvalidOperationException()
};
}
}
} }

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using Content.Shared.GameObjects.Components;
using NUnit.Framework;
using Robust.UnitTesting;
using static Content.Shared.GameObjects.Components.SharedWiresComponent;
namespace Content.Tests.Shared
{
// Making sure nobody forgets to set values for these wire colors/letters.
// Also a thinly veiled excuse to bloat the test count.
[TestFixture]
public class WireHackingTest : RobustUnitTest
{
public static IEnumerable<WireColor> ColorValues = (WireColor[]) Enum.GetValues(typeof(WireColor));
public static IEnumerable<WireLetter> LetterValues = (WireLetter[]) Enum.GetValues(typeof(WireLetter));
[Test]
public void TestColorNameExists([ValueSource(nameof(ColorValues))] WireColor color)
{
Assert.DoesNotThrow(() => color.Name());
}
[Test]
public void TestColorValueExists([ValueSource(nameof(ColorValues))] WireColor color)
{
Assert.DoesNotThrow(() => color.ColorValue());
}
[Test]
public void TestLetterNameExists([ValueSource(nameof(LetterValues))] WireLetter letter)
{
Assert.DoesNotThrow(() => letter.Name());
}
[Test]
public void TestLetterLetterExists([ValueSource(nameof(LetterValues))] WireLetter letter)
{
Assert.DoesNotThrow(() => letter.Letter());
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,2 @@
https://fontlibrary.org/en/font/boxfont-round
License: CC-0

View File

@@ -42,6 +42,8 @@
- type: WiresVisualizer2D - type: WiresVisualizer2D
- type: PowerDevice - type: PowerDevice
- type: Wires - type: Wires
BoardName: "Airlock Control"
LayoutId: Airlock
- type: UserInterface - type: UserInterface
interfaces: interfaces:
- key: enum.WiresUiKey.Key - key: enum.WiresUiKey.Key

View File

@@ -44,6 +44,8 @@
- type: PowerDevice - type: PowerDevice
priority: Low priority: Low
- type: Wires - type: Wires
BoardName: "Vending Machine"
LayoutId: Vending
- type: Anchorable - type: Anchorable
- type: entity - type: entity

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/contact.svg.96dpi.png"
sodipodi:docname="contact.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg1055"
version="1.1"
viewBox="0 0 5.2916665 5.2916667"
height="20"
width="20">
<defs
id="defs1049" />
<sodipodi:namedview
inkscape:document-rotation="0"
inkscape:snap-page="true"
units="px"
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="1043"
inkscape:window-width="1920"
inkscape:pagecheckerboard="true"
showgrid="false"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="13.143062"
inkscape:cx="7.9388602"
inkscape:zoom="16.596042"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata1052">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-79.848503,-133.93878)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Nano/button.svg.96dpi.png"
sodipodi:nodetypes="ccccccc"
inkscape:connector-curvature="0"
id="rect1684"
d="m 79.848503,133.93878 v 4.23333 l 1.058333,1.05834 4.233334,0 v -4.23334 l -1.058334,-1.05833 z"
style="opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.672306;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="10"
height="10"
viewBox="0 0 2.6458333 2.6458334"
version="1.1"
id="svg1067"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="light_off_base.svg"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/light_off_base.svg.96dpi.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs1061" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="48.200006"
inkscape:cx="5.9595811"
inkscape:cy="6.1399278"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
inkscape:pagecheckerboard="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata1064">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<circle
r="1.3229166"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.822271;stroke-linejoin:round;stop-color:#000000"
id="path1630"
cx="1.3229166"
cy="1.3229166" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/light_on_base.svg.96dpi.png"
sodipodi:docname="light_on_base.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg1656"
version="1.1"
viewBox="0 0 5.2916665 5.2916668"
height="20"
width="20">
<defs
id="defs1650" />
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="1043"
inkscape:window-width="1920"
inkscape:pagecheckerboard="true"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="13.844648"
inkscape:cx="10.215346"
inkscape:zoom="32.858486"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata1653">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<circle
r="2.6458333"
cy="2.6458333"
cx="2.6458333"
id="path2219"
style="fill:#ffffff;stroke-width:4.8121;stroke-linejoin:round;stop-color:#000000" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/wire_1.svg.96dpi.png"
sodipodi:docname="wire_1.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg2245"
version="1.1"
viewBox="0 0 4.2333332 13.229168"
height="50"
width="16">
<defs
id="defs2239" />
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="1043"
inkscape:window-width="1920"
inkscape:pagecheckerboard="true"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="32.466344"
inkscape:cx="0.28200599"
inkscape:zoom="16"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata2242">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/path2808.png"
sodipodi:nodetypes="cssssc"
id="path2808"
d="m 2.1166667,0 v 0.79613126 c 0,0.78760474 -1.0120136,2.42170104 -0.793751,3.17261784 C 1.4470644,4.3958736 3.8422507,6.0675058 2.554148,7.5607995 0.659652,9.7570832 2.1232809,10.802432 2.1232809,11.958902 v 1.270265"
style="fill:none;stroke:#ffffff;stroke-width:1.45521169;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="50"
viewBox="0 0 4.2333332 13.229168"
version="1.1"
id="svg2245"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="wire_1_copper.svg"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/wire_1_copper.svg.96dpi.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2239" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16.596042"
inkscape:cx="3.6251654"
inkscape:cy="20.811313"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata2242">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.1166667,0.79613126 c 0,0.71990754 -1.0996836,1.90834794 -1.1076036,2.68421504 0,0 1.0503303,1.4967767 1.2175433,1.8433776 m 1.0130953,1.4005037 c 0,0 -0.3977935,1.5923631 -0.4631103,1.6724885 C 1.1487967,10.393567 2.1232809,10.847046 2.1232809,11.958902"
id="path2808"
sodipodi:nodetypes="csccsc"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/path2808.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/wire_1_cut.svg.96dpi.png"
sodipodi:docname="wire_1_cut.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg2245"
version="1.1"
viewBox="0 0 4.2333332 13.229168"
height="50"
width="16">
<defs
id="defs2239" />
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="1043"
inkscape:window-width="1920"
inkscape:pagecheckerboard="true"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="32.466344"
inkscape:cx="0.28200599"
inkscape:zoom="16"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata2242">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/path2808.png"
sodipodi:nodetypes="cssccssc"
id="path2808"
d="m 2.1166667,0 v 0.79613126 c 0,0.71990754 -1.0996836,1.90834794 -1.1076036,2.68421504 0,0 0.6326351,0.8654513 0.7998481,1.2120522 m 1.1950287,2.7625683 c 0,0 -0.1620317,0.8616239 -0.2273485,0.9417493 C 1.1487967,10.393567 2.1232809,10.847046 2.1232809,11.958902 v 1.270265"
style="fill:none;stroke:#ffffff;stroke-width:1.45521;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="50"
viewBox="0 0 4.2333332 13.229168"
version="1.1"
id="svg2245"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="wire_2.svg"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/wire_2.svg.96dpi.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2239" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="16.596042"
inkscape:cx="5.0983612"
inkscape:cy="25.635501"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata2242">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#ffffff;stroke-width:1.45521;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.1166667,0 v 0.79613126 c 0,0.78760474 -0.5971633,2.27740564 -0.3789007,3.02832244 0.1241487,0.4271245 0.7517153,2.4865506 0.3834964,3.7183084 -0.8307376,2.7789659 0.00202,3.2596699 0.00202,4.4161399 v 1.270265"
id="path2808"
sodipodi:nodetypes="cssssc"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/path2808.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/wire_copper_2.svg.96dpi.png"
sodipodi:docname="wire_2_copper.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg2245"
version="1.1"
viewBox="0 0 4.2333332 13.229168"
height="50"
width="16">
<defs
id="defs2239" />
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-height="1043"
inkscape:window-width="1920"
inkscape:pagecheckerboard="true"
units="px"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="px"
inkscape:cy="24.153232"
inkscape:cx="6.7373069"
inkscape:zoom="17.214288"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata2242">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<path
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/path2808.png"
sodipodi:nodetypes="cssccssc"
id="path2808"
d="m 2.1166667,0 v 0.79613126 c 0,0.63154634 -0.3962617,2.17791674 -0.4407643,3.15307984 -0.010997,0.240968 0.1844183,1.1549069 0.2276656,1.3036958 m 0.5110368,1.2695316 c -0.020506,0.068595 -0.2186245,0.72274 -0.2372771,0.7890946 -0.7370104,2.6218434 -0.054045,3.5194449 -0.054045,4.6473689 v 1.270265"
style="fill:none;stroke:#ffffff;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="50"
viewBox="0 0 4.2333332 13.229168"
version="1.1"
id="svg2245"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="wire_2_cut.svg"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/wire_2_cut.svg.96dpi.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2239" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="17.855565"
inkscape:cx="5.0983612"
inkscape:cy="25.635501"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:pagecheckerboard="true"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1" />
<metadata
id="metadata2242">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#ffffff;stroke-width:1.45521;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 2.1166667,0 v 0.79613126 c 0,0.78760474 -0.6162946,2.99800944 -0.398032,3.74892624 M 2.3427376,7.5240277 C 1.512,10.302994 2.1232824,10.802432 2.1232824,11.958902 v 1.270265"
id="path2808"
sodipodi:nodetypes="csccsc"
inkscape:export-filename="/ssdhome/pj/Projects/space-station-14-content/Resources/Textures/UserInterface/WireHacking/path2808.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

View File

@@ -0,0 +1,2 @@
sample:
filter: true