Nerf hacking a smidge (#5940)
This commit is contained in:
@@ -1,7 +1,16 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using Content.Server.Tools;
|
||||||
|
using Content.Server.VendingMachines;
|
||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.GameTicking;
|
using Content.Shared.GameTicking;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
using static Content.Shared.Wires.SharedWiresComponent;
|
using static Content.Shared.Wires.SharedWiresComponent;
|
||||||
|
|
||||||
@@ -9,6 +18,10 @@ namespace Content.Server.WireHacking
|
|||||||
{
|
{
|
||||||
public class WireHackingSystem : EntitySystem
|
public class WireHackingSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
|
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
|
||||||
|
[Dependency] private readonly ToolSystem _tools = default!;
|
||||||
|
|
||||||
[ViewVariables] private readonly Dictionary<string, WireLayout> _layouts =
|
[ViewVariables] private readonly Dictionary<string, WireLayout> _layouts =
|
||||||
new();
|
new();
|
||||||
|
|
||||||
@@ -18,23 +31,184 @@ namespace Content.Server.WireHacking
|
|||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<WiresComponent, ComponentStartup>(OnWiresStartup);
|
||||||
|
SubscribeLocalEvent<WiresComponent, MapInitEvent>(OnWiresMapInit);
|
||||||
|
SubscribeLocalEvent<WiresComponent, ExaminedEvent>(OnWiresExamine);
|
||||||
|
|
||||||
|
// Hacking DoAfters
|
||||||
|
SubscribeLocalEvent<WiresComponent, WiresComponent.WiresCutEvent>(OnWiresCut);
|
||||||
|
SubscribeLocalEvent<WiresComponent, WiresComponent.WiresMendedEvent>(OnWiresMended);
|
||||||
|
SubscribeLocalEvent<WiresComponent, WiresComponent.WiresPulsedEvent>(OnWiresPulsed);
|
||||||
|
SubscribeLocalEvent<WiresComponent, WiresComponent.WiresCancelledEvent>(OnWiresCancelled);
|
||||||
|
|
||||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetLayout(string id, [NotNullWhen(true)] out WireLayout? layout)
|
private void OnWiresCancelled(EntityUid uid, WiresComponent component, WiresComponent.WiresCancelledEvent args)
|
||||||
{
|
{
|
||||||
return _layouts.TryGetValue(id, out layout);
|
component.PendingDoAfters.Remove(args.Wire.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddLayout(string id, WireLayout layout)
|
private void HackingInteract(WiresComponent component, WiresComponent.Wire wire)
|
||||||
{
|
{
|
||||||
_layouts.Add(id, layout);
|
component.PendingDoAfters.Remove(wire.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset(RoundRestartCleanupEvent ev)
|
private void OnWiresCut(EntityUid uid, WiresComponent component, WiresComponent.WiresCutEvent args)
|
||||||
|
{
|
||||||
|
HackingInteract(component, args.Wire);
|
||||||
|
|
||||||
|
// Re-validate
|
||||||
|
// Deletion for user + wires should already be handled by do-after and tool is checked once at end in active-hand anyway.
|
||||||
|
if (!component.CanWiresInteract(args.User, out var tool)) return;
|
||||||
|
|
||||||
|
if (!tool.Qualities.Contains(component.CuttingQuality)) return;
|
||||||
|
|
||||||
|
var wire = args.Wire;
|
||||||
|
|
||||||
|
_tools.PlayToolSound(args.Tool.Owner, args.Tool);
|
||||||
|
wire.IsCut = true;
|
||||||
|
component.UpdateUserInterface();
|
||||||
|
|
||||||
|
wire.Owner.WiresUpdate(new WiresUpdateEventArgs(wire.Identifier, WiresAction.Cut));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWiresMended(EntityUid uid, WiresComponent component, WiresComponent.WiresMendedEvent args)
|
||||||
|
{
|
||||||
|
HackingInteract(component, args.Wire);
|
||||||
|
|
||||||
|
if (!component.CanWiresInteract(args.User, out var tool)) return;
|
||||||
|
|
||||||
|
if (!tool.Qualities.Contains(component.CuttingQuality)) return;
|
||||||
|
|
||||||
|
var wire = args.Wire;
|
||||||
|
|
||||||
|
_tools.PlayToolSound(args.Tool.Owner, args.Tool);
|
||||||
|
wire.IsCut = false;
|
||||||
|
component.UpdateUserInterface();
|
||||||
|
|
||||||
|
wire.Owner.WiresUpdate(new WiresUpdateEventArgs(wire.Identifier, WiresAction.Mend));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWiresPulsed(EntityUid uid, WiresComponent component, WiresComponent.WiresPulsedEvent args)
|
||||||
|
{
|
||||||
|
HackingInteract(component, args.Wire);
|
||||||
|
|
||||||
|
if (args.Wire.IsCut || !component.CanWiresInteract(args.User, out var tool)) return;
|
||||||
|
|
||||||
|
if (!tool.Qualities.Contains(component.PulsingQuality)) return;
|
||||||
|
|
||||||
|
var wire = args.Wire;
|
||||||
|
SoundSystem.Play(Filter.Pvs(uid), component.PulseSound.GetSound(), uid);
|
||||||
|
wire.Owner.WiresUpdate(new WiresUpdateEventArgs(wire.Identifier, WiresAction.Pulse));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWiresExamine(EntityUid uid, WiresComponent component, ExaminedEvent args)
|
||||||
|
{
|
||||||
|
args.PushMarkup(Loc.GetString(component.IsPanelOpen
|
||||||
|
? "wires-component-on-examine-panel-open"
|
||||||
|
: "wires-component-on-examine-panel-closed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWiresStartup(EntityUid uid, WiresComponent component, ComponentStartup args)
|
||||||
|
{
|
||||||
|
WireLayout? layout = null;
|
||||||
|
if (component.LayoutId != null)
|
||||||
|
{
|
||||||
|
_layouts.TryGetValue(component.LayoutId, out layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var wiresProvider in EntityManager.GetComponents<IWires>(uid))
|
||||||
|
{
|
||||||
|
var builder = new WiresComponent.WiresBuilder(component, wiresProvider, layout);
|
||||||
|
wiresProvider.RegisterWires(builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layout != null)
|
||||||
|
{
|
||||||
|
component.WiresList.Sort((a, b) =>
|
||||||
|
{
|
||||||
|
var pA = layout.Specifications[a.Identifier].Position;
|
||||||
|
var pB = layout.Specifications[b.Identifier].Position;
|
||||||
|
|
||||||
|
return pA.CompareTo(pB);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_random.Shuffle(component.WiresList);
|
||||||
|
|
||||||
|
if (component.LayoutId != null)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<object, WireLayout.WireData>();
|
||||||
|
for (var i = 0; i < component.WiresList.Count; i++)
|
||||||
|
{
|
||||||
|
var d = component.WiresList[i];
|
||||||
|
dict.Add(d.Identifier, new WireLayout.WireData(d.Letter, d.Color, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
_layouts.Add(component.LayoutId, new WireLayout(dict));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = 0;
|
||||||
|
foreach (var wire in component.WiresList)
|
||||||
|
{
|
||||||
|
wire.Id = ++id;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.UpdateUserInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Reset(RoundRestartCleanupEvent ev)
|
||||||
{
|
{
|
||||||
_layouts.Clear();
|
_layouts.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnWiresMapInit(EntityUid uid, WiresComponent component, MapInitEvent args)
|
||||||
|
{
|
||||||
|
if (component.SerialNumber == null)
|
||||||
|
{
|
||||||
|
GenerateSerialNumber(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.WireSeed == 0)
|
||||||
|
{
|
||||||
|
component.WireSeed = _random.Next(1, int.MaxValue);
|
||||||
|
component.UpdateUserInterface();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateSerialNumber(WiresComponent component)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
component.SerialNumber = new string(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class WireLayout
|
public sealed class WireLayout
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.DoAfter;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Tools;
|
using Content.Server.Tools;
|
||||||
using Content.Server.Tools.Components;
|
using Content.Server.Tools.Components;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Server.VendingMachines;
|
using Content.Server.VendingMachines;
|
||||||
using Content.Shared.Examine;
|
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -24,29 +25,37 @@ using Robust.Shared.Player;
|
|||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Server.WireHacking
|
namespace Content.Server.WireHacking
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
#pragma warning disable 618
|
public class WiresComponent : SharedWiresComponent, IInteractUsing
|
||||||
public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit
|
|
||||||
#pragma warning restore 618
|
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly IEntityManager _entities = default!;
|
[Dependency] private readonly IEntityManager _entities = default!;
|
||||||
|
|
||||||
private bool _isPanelOpen;
|
private bool _isPanelOpen;
|
||||||
|
|
||||||
|
[DataField("cuttingTime")] public float CuttingTime = 1f;
|
||||||
|
|
||||||
|
[DataField("mendTime")] public float MendTime = 1f;
|
||||||
|
|
||||||
|
[DataField("pulseTime")] public float PulseTime = 3f;
|
||||||
|
|
||||||
[DataField("screwingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
[DataField("screwingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
||||||
private string _screwingQuality = "Screwing";
|
public string ScrewingQuality = "Screwing";
|
||||||
|
|
||||||
[DataField("cuttingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
[DataField("cuttingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
||||||
private string _cuttingQuality = "Cutting";
|
public string CuttingQuality = "Cutting";
|
||||||
|
|
||||||
[DataField("pulsingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
[DataField("pulsingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
||||||
private string _pulsingQuality = "Pulsing";
|
public string PulsingQuality = "Pulsing";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Make do_afters for hacking unique per wire so we can't spam a single wire.
|
||||||
|
/// </summary>
|
||||||
|
public HashSet<int> PendingDoAfters = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opening the maintenance panel (typically with a screwdriver) changes this.
|
/// Opening the maintenance panel (typically with a screwdriver) changes this.
|
||||||
@@ -152,13 +161,12 @@ namespace Content.Server.WireHacking
|
|||||||
// We honestly don't care what it is or such but do care that it doesn't change between UI re-opens.
|
// We honestly don't care what it is or such but do care that it doesn't change between UI re-opens.
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
[DataField("WireSeed")]
|
[DataField("WireSeed")]
|
||||||
private int _wireSeed;
|
public int WireSeed;
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
[DataField("LayoutId")]
|
[DataField("LayoutId")]
|
||||||
private string? _layoutId = default;
|
public string? LayoutId = default;
|
||||||
|
|
||||||
[DataField("pulseSound")]
|
[DataField("pulseSound")] public SoundSpecifier PulseSound = new SoundPathSpecifier("/Audio/Effects/multitool_pulse.ogg");
|
||||||
private SoundSpecifier _pulseSound = new SoundPathSpecifier("/Audio/Effects/multitool_pulse.ogg");
|
|
||||||
|
|
||||||
[DataField("screwdriverOpenSound")]
|
[DataField("screwdriverOpenSound")]
|
||||||
private SoundSpecifier _screwdriverOpenSound = new SoundPathSpecifier("/Audio/Machines/screwdriveropen.ogg");
|
private SoundSpecifier _screwdriverOpenSound = new SoundPathSpecifier("/Audio/Machines/screwdriveropen.ogg");
|
||||||
@@ -183,92 +191,6 @@ namespace Content.Server.WireHacking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
base.Startup();
|
|
||||||
|
|
||||||
|
|
||||||
WireLayout? layout = null;
|
|
||||||
var hackingSystem = EntitySystem.Get<WireHackingSystem>();
|
|
||||||
if (_layoutId != null)
|
|
||||||
{
|
|
||||||
hackingSystem.TryGetLayout(_layoutId, out layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var wiresProvider in _entities.GetComponents<IWires>(Owner))
|
|
||||||
{
|
|
||||||
var builder = new WiresBuilder(this, wiresProvider, layout);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns whether the wire associated with <see cref="identifier"/> is cut.
|
/// Returns whether the wire associated with <see cref="identifier"/> is cut.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -400,6 +322,31 @@ namespace Content.Server.WireHacking
|
|||||||
UserInterface?.CloseAll();
|
UserInterface?.CloseAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanWiresInteract(EntityUid user, [NotNullWhen(true)] out ToolComponent? tool)
|
||||||
|
{
|
||||||
|
tool = null;
|
||||||
|
|
||||||
|
if (!_entities.TryGetComponent(user, out HandsComponent? handsComponent))
|
||||||
|
{
|
||||||
|
Owner.PopupMessage(user, Loc.GetString("wires-component-ui-on-receive-message-no-hands"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!user.InRangeUnobstructed(Owner))
|
||||||
|
{
|
||||||
|
Owner.PopupMessage(user, Loc.GetString("wires-component-ui-on-receive-message-cannot-reach"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handsComponent.GetActiveHand()?.HeldEntity is not { Valid: true } activeHandEntity ||
|
||||||
|
!_entities.TryGetComponent(activeHandEntity, out tool))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
|
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
|
||||||
{
|
{
|
||||||
var message = serverMsg.Message;
|
var message = serverMsg.Message;
|
||||||
@@ -407,54 +354,74 @@ namespace Content.Server.WireHacking
|
|||||||
{
|
{
|
||||||
case WiresActionMessage msg:
|
case WiresActionMessage msg:
|
||||||
var wire = WiresList.Find(x => x.Id == msg.Id);
|
var wire = WiresList.Find(x => x.Id == msg.Id);
|
||||||
if (wire == null || serverMsg.Session.AttachedEntity is not {} player)
|
if (wire == null ||
|
||||||
|
serverMsg.Session.AttachedEntity is not {} player ||
|
||||||
|
PendingDoAfters.Contains(wire.Id))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_entities.TryGetComponent(player, out HandsComponent? handsComponent))
|
if (!CanWiresInteract(player, out var tool))
|
||||||
{
|
|
||||||
Owner.PopupMessage(player, Loc.GetString("wires-component-ui-on-receive-message-no-hands"));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!player.InRangeUnobstructed(Owner))
|
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
||||||
{
|
|
||||||
Owner.PopupMessage(player, Loc.GetString("wires-component-ui-on-receive-message-cannot-reach"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolComponent? tool = null;
|
|
||||||
if (handsComponent.GetActiveHandItem?.Owner is EntityUid activeHandEntity)
|
|
||||||
_entities.TryGetComponent(activeHandEntity, out tool);
|
|
||||||
var toolSystem = EntitySystem.Get<ToolSystem>();
|
|
||||||
|
|
||||||
switch (msg.Action)
|
switch (msg.Action)
|
||||||
{
|
{
|
||||||
case WiresAction.Cut:
|
case WiresAction.Cut:
|
||||||
if (tool == null || !tool.Qualities.Contains(_cuttingQuality))
|
if (!tool.Qualities.Contains(CuttingQuality))
|
||||||
{
|
{
|
||||||
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toolSystem.PlayToolSound(tool.Owner, tool);
|
doAfterSystem.DoAfter(
|
||||||
wire.IsCut = true;
|
new DoAfterEventArgs(player, CuttingTime, target: Owner)
|
||||||
UpdateUserInterface();
|
{
|
||||||
|
TargetFinishedEvent = new WiresCutEvent
|
||||||
|
{
|
||||||
|
Wire = wire,
|
||||||
|
Tool = tool,
|
||||||
|
User = player,
|
||||||
|
},
|
||||||
|
TargetCancelledEvent = new WiresCancelledEvent()
|
||||||
|
{
|
||||||
|
Wire = wire,
|
||||||
|
},
|
||||||
|
NeedHand = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
PendingDoAfters.Add(wire.Id);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case WiresAction.Mend:
|
case WiresAction.Mend:
|
||||||
if (tool == null || !tool.Qualities.Contains(_cuttingQuality))
|
if (!tool.Qualities.Contains(CuttingQuality))
|
||||||
{
|
{
|
||||||
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toolSystem.PlayToolSound(tool.Owner, tool);
|
doAfterSystem.DoAfter(
|
||||||
wire.IsCut = false;
|
new DoAfterEventArgs(player, MendTime, target: Owner)
|
||||||
UpdateUserInterface();
|
{
|
||||||
|
TargetFinishedEvent = new WiresMendedEvent()
|
||||||
|
{
|
||||||
|
Wire = wire,
|
||||||
|
Tool = tool,
|
||||||
|
User = player,
|
||||||
|
},
|
||||||
|
TargetCancelledEvent = new WiresCancelledEvent()
|
||||||
|
{
|
||||||
|
Wire = wire,
|
||||||
|
},
|
||||||
|
NeedHand = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
PendingDoAfters.Add(wire.Id);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case WiresAction.Pulse:
|
case WiresAction.Pulse:
|
||||||
if (tool == null || !tool.Qualities.Contains(_pulsingQuality))
|
if (!tool.Qualities.Contains(PulsingQuality))
|
||||||
{
|
{
|
||||||
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
||||||
return;
|
return;
|
||||||
@@ -466,16 +433,56 @@ namespace Content.Server.WireHacking
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SoundSystem.Play(Filter.Pvs(Owner), _pulseSound.GetSound(), Owner);
|
doAfterSystem.DoAfter(
|
||||||
|
new DoAfterEventArgs(player, PulseTime, target: Owner)
|
||||||
|
{
|
||||||
|
TargetFinishedEvent = new WiresPulsedEvent
|
||||||
|
{
|
||||||
|
Wire = wire,
|
||||||
|
Tool = tool,
|
||||||
|
User = player,
|
||||||
|
},
|
||||||
|
TargetCancelledEvent = new WiresCancelledEvent()
|
||||||
|
{
|
||||||
|
Wire = wire,
|
||||||
|
},
|
||||||
|
NeedHand = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
PendingDoAfters.Add(wire.Id);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
wire.Owner.WiresUpdate(new WiresUpdateEventArgs(wire.Identifier, msg.Action));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateUserInterface()
|
public sealed class WiresCancelledEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public Wire Wire { get; init; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class WiresEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public EntityUid User { get; init; } = default!;
|
||||||
|
public Wire Wire { get; init; } = default!;
|
||||||
|
public ToolComponent Tool { get; init; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class WiresCutEvent : WiresEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class WiresMendedEvent : WiresEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class WiresPulsedEvent : WiresEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void UpdateUserInterface()
|
||||||
{
|
{
|
||||||
var clientList = new List<ClientWire>();
|
var clientList = new List<ClientWire>();
|
||||||
foreach (var entry in WiresList)
|
foreach (var entry in WiresList)
|
||||||
@@ -490,7 +497,7 @@ namespace Content.Server.WireHacking
|
|||||||
_statuses.Select(p => new StatusEntry(p.Key, p.Value)).ToArray(),
|
_statuses.Select(p => new StatusEntry(p.Key, p.Value)).ToArray(),
|
||||||
BoardName,
|
BoardName,
|
||||||
SerialNumber,
|
SerialNumber,
|
||||||
_wireSeed));
|
WireSeed));
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
@@ -504,8 +511,8 @@ namespace Content.Server.WireHacking
|
|||||||
|
|
||||||
// opens the wires ui if using a tool with cutting or multitool quality on it
|
// opens the wires ui if using a tool with cutting or multitool quality on it
|
||||||
if (IsPanelOpen &&
|
if (IsPanelOpen &&
|
||||||
(tool.Qualities.Contains(_cuttingQuality) ||
|
(tool.Qualities.Contains(CuttingQuality) ||
|
||||||
tool.Qualities.Contains(_pulsingQuality)))
|
tool.Qualities.Contains(PulsingQuality)))
|
||||||
{
|
{
|
||||||
if (_entities.TryGetComponent(eventArgs.User, out ActorComponent? actor))
|
if (_entities.TryGetComponent(eventArgs.User, out ActorComponent? actor))
|
||||||
{
|
{
|
||||||
@@ -516,7 +523,7 @@ namespace Content.Server.WireHacking
|
|||||||
|
|
||||||
// screws the panel open if the tool can do so
|
// screws the panel open if the tool can do so
|
||||||
else if (await toolSystem.UseTool(tool.Owner, eventArgs.User, Owner,
|
else if (await toolSystem.UseTool(tool.Owner, eventArgs.User, Owner,
|
||||||
0f, WireHackingSystem.ScrewTime, _screwingQuality, toolComponent:tool))
|
0f, WireHackingSystem.ScrewTime, ScrewingQuality, toolComponent:tool))
|
||||||
{
|
{
|
||||||
IsPanelOpen = !IsPanelOpen;
|
IsPanelOpen = !IsPanelOpen;
|
||||||
if (IsPanelOpen)
|
if (IsPanelOpen)
|
||||||
@@ -534,13 +541,6 @@ namespace Content.Server.WireHacking
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IExamine.Examine(FormattedMessage message, bool inDetailsRange)
|
|
||||||
{
|
|
||||||
message.AddMarkup(Loc.GetString(IsPanelOpen
|
|
||||||
? "wires-component-on-examine-panel-open"
|
|
||||||
: "wires-component-on-examine-panel-closed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetStatus(object statusIdentifier, object status)
|
public void SetStatus(object statusIdentifier, object status)
|
||||||
{
|
{
|
||||||
if (_statuses.TryGetValue(statusIdentifier, out var storedMessage))
|
if (_statuses.TryGetValue(statusIdentifier, out var storedMessage))
|
||||||
@@ -554,19 +554,5 @@ namespace Content.Server.WireHacking
|
|||||||
_statuses[statusIdentifier] = status;
|
_statuses[statusIdentifier] = status;
|
||||||
UpdateUserInterface();
|
UpdateUserInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMapInit.MapInit()
|
|
||||||
{
|
|
||||||
if (SerialNumber == null)
|
|
||||||
{
|
|
||||||
GenerateSerialNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_wireSeed == 0)
|
|
||||||
{
|
|
||||||
_wireSeed = IoCManager.Resolve<IRobustRandom>().Next(1, int.MaxValue);
|
|
||||||
UpdateUserInterface();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Command"]]
|
access: [["Command"]]
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: AirlockCommand
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockCommand
|
parent: AirlockCommand
|
||||||
@@ -199,6 +201,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Security"]]
|
access: [["Security"]]
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: AirlockSecurity
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockSecurity
|
parent: AirlockSecurity
|
||||||
@@ -207,6 +211,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Armory"]]
|
access: [["Armory"]]
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: AirlockArmory
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: AirlockSecurity
|
parent: AirlockSecurity
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
map: ["enum.DoorVisualLayers.BaseBolted"]
|
map: ["enum.DoorVisualLayers.BaseBolted"]
|
||||||
- state: panel_open
|
- state: panel_open
|
||||||
map: ["enum.WiresVisualLayers.MaintenancePanel"]
|
map: ["enum.WiresVisualLayers.MaintenancePanel"]
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: Docking
|
||||||
- type: Door
|
- type: Door
|
||||||
bumpOpen: false
|
bumpOpen: false
|
||||||
closeTimeTwo: 0.4
|
closeTimeTwo: 0.4
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
path: /Audio/Machines/airlock_deny.ogg
|
path: /Audio/Machines/airlock_deny.ogg
|
||||||
- type: Wires
|
- type: Wires
|
||||||
BoardName: "Windoor Control"
|
BoardName: "Windoor Control"
|
||||||
LayoutId: Airlock
|
LayoutId: Windoors
|
||||||
- type: UserInterface
|
- type: UserInterface
|
||||||
interfaces:
|
interfaces:
|
||||||
- key: enum.WiresUiKey.Key
|
- key: enum.WiresUiKey.Key
|
||||||
@@ -126,6 +126,8 @@
|
|||||||
- state: panel_open
|
- state: panel_open
|
||||||
map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
|
map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
|
||||||
visible: false
|
visible: false
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: Secure Windoors
|
||||||
- type: Destructible
|
- type: Destructible
|
||||||
thresholds:
|
thresholds:
|
||||||
- trigger:
|
- trigger:
|
||||||
|
|||||||
@@ -55,6 +55,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Command"]]
|
access: [["Command"]]
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: WindoorCommand
|
||||||
|
|
||||||
# Cargo windoor
|
# Cargo windoor
|
||||||
- type: entity
|
- type: entity
|
||||||
@@ -73,6 +75,8 @@
|
|||||||
components:
|
components:
|
||||||
- type: AccessReader
|
- type: AccessReader
|
||||||
access: [["Security"]]
|
access: [["Security"]]
|
||||||
|
- type: Wires
|
||||||
|
LayoutId: WindoorSecurity
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: WindoorSecure
|
parent: WindoorSecure
|
||||||
|
|||||||
Reference in New Issue
Block a user