2020-07-08 01:41:20 +02:00
|
|
|
|
using System;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
using System.Collections.Generic;
|
2022-01-26 15:26:53 +11:00
|
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2019-09-06 10:05:02 +02:00
|
|
|
|
using System.Linq;
|
2020-08-18 14:39:08 +02:00
|
|
|
|
using System.Threading.Tasks;
|
2022-01-26 15:26:53 +11:00
|
|
|
|
using Content.Server.DoAfter;
|
2021-06-09 22:19:39 +02:00
|
|
|
|
using Content.Server.Hands.Components;
|
2021-10-07 13:01:27 +02:00
|
|
|
|
using Content.Server.Tools;
|
2021-06-09 22:19:39 +02:00
|
|
|
|
using Content.Server.Tools.Components;
|
|
|
|
|
|
using Content.Server.UserInterface;
|
|
|
|
|
|
using Content.Server.VendingMachines;
|
|
|
|
|
|
using Content.Shared.Interaction;
|
2021-12-06 15:39:46 +11:00
|
|
|
|
using Content.Shared.Interaction.Helpers;
|
|
|
|
|
|
using Content.Shared.Popups;
|
2021-07-10 17:35:33 +02:00
|
|
|
|
using Content.Shared.Sound;
|
2021-10-07 13:01:27 +02:00
|
|
|
|
using Content.Shared.Tools;
|
2021-06-09 22:19:39 +02:00
|
|
|
|
using Content.Shared.Wires;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
using Robust.Server.GameObjects;
|
2021-02-11 01:13:03 -08:00
|
|
|
|
using Robust.Server.Player;
|
2021-03-21 09:12:03 -07:00
|
|
|
|
using Robust.Shared.Audio;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
using Robust.Shared.GameObjects;
|
|
|
|
|
|
using Robust.Shared.IoC;
|
|
|
|
|
|
using Robust.Shared.Localization;
|
2021-03-21 09:12:03 -07:00
|
|
|
|
using Robust.Shared.Player;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
using Robust.Shared.Random;
|
2021-03-05 01:08:38 +01:00
|
|
|
|
using Robust.Shared.Serialization.Manager.Attributes;
|
2021-10-07 13:01:27 +02:00
|
|
|
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
2020-05-27 15:09:22 +02:00
|
|
|
|
using Robust.Shared.ViewVariables;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
|
2021-07-04 18:11:52 +02:00
|
|
|
|
namespace Content.Server.WireHacking
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
[RegisterComponent]
|
2022-02-16 00:23:23 -07:00
|
|
|
|
public sealed class WiresComponent : SharedWiresComponent, IInteractUsing
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2020-07-08 01:41:20 +02:00
|
|
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
2021-12-05 18:09:01 +01:00
|
|
|
|
[Dependency] private readonly IEntityManager _entities = default!;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
|
2019-09-18 22:12:36 +02:00
|
|
|
|
private bool _isPanelOpen;
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
[DataField("cuttingTime")] public float CuttingTime = 1f;
|
|
|
|
|
|
|
|
|
|
|
|
[DataField("mendTime")] public float MendTime = 1f;
|
|
|
|
|
|
|
|
|
|
|
|
[DataField("pulseTime")] public float PulseTime = 3f;
|
|
|
|
|
|
|
2021-10-07 13:01:27 +02:00
|
|
|
|
[DataField("screwingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
2022-01-26 15:26:53 +11:00
|
|
|
|
public string ScrewingQuality = "Screwing";
|
2021-10-07 13:01:27 +02:00
|
|
|
|
|
|
|
|
|
|
[DataField("cuttingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
2022-01-26 15:26:53 +11:00
|
|
|
|
public string CuttingQuality = "Cutting";
|
2021-10-07 13:01:27 +02:00
|
|
|
|
|
|
|
|
|
|
[DataField("pulsingQuality", customTypeSerializer:typeof(PrototypeIdSerializer<ToolQualityPrototype>))]
|
2022-01-26 15:26:53 +11:00
|
|
|
|
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();
|
2021-10-07 13:01:27 +02:00
|
|
|
|
|
2019-09-18 22:12:36 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Opening the maintenance panel (typically with a screwdriver) changes this.
|
|
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
[ViewVariables]
|
2019-09-18 22:12:36 +02:00
|
|
|
|
public bool IsPanelOpen
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2019-09-18 22:12:36 +02:00
|
|
|
|
get => _isPanelOpen;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
private set
|
|
|
|
|
|
{
|
2019-09-18 22:12:36 +02:00
|
|
|
|
if (_isPanelOpen == value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2019-09-18 22:12:36 +02:00
|
|
|
|
_isPanelOpen = value;
|
2020-10-13 11:42:12 +02:00
|
|
|
|
|
|
|
|
|
|
if (!_isPanelOpen)
|
|
|
|
|
|
UserInterface?.CloseAll();
|
2019-09-18 22:12:36 +02:00
|
|
|
|
UpdateAppearance();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _isPanelVisible = true;
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2019-09-18 22:12:36 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Components can set this to prevent the maintenance panel overlay from showing even if it's open
|
|
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
[ViewVariables]
|
2019-09-18 22:12:36 +02:00
|
|
|
|
public bool IsPanelVisible
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _isPanelVisible;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_isPanelVisible == value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2019-09-18 22:12:36 +02:00
|
|
|
|
_isPanelVisible = value;
|
|
|
|
|
|
UpdateAppearance();
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-27 15:09:22 +02:00
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
|
|
|
|
|
public string BoardName
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _boardName;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_boardName = value;
|
|
|
|
|
|
UpdateUserInterface();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[ViewVariables(VVAccess.ReadWrite)]
|
2020-07-08 01:41:20 +02:00
|
|
|
|
public string? SerialNumber
|
2020-05-27 15:09:22 +02:00
|
|
|
|
{
|
|
|
|
|
|
get => _serialNumber;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_serialNumber = value;
|
|
|
|
|
|
UpdateUserInterface();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-18 22:12:36 +02:00
|
|
|
|
private void UpdateAppearance()
|
|
|
|
|
|
{
|
2021-12-05 18:09:01 +01:00
|
|
|
|
if (_entities.TryGetComponent(Owner, out AppearanceComponent? appearance))
|
2020-08-24 13:39:00 +02:00
|
|
|
|
{
|
|
|
|
|
|
appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen && IsPanelVisible);
|
|
|
|
|
|
}
|
2019-09-18 22:12:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Contains all registered wires.
|
|
|
|
|
|
/// </summary>
|
2020-09-08 13:30:22 +02:00
|
|
|
|
[ViewVariables]
|
2020-11-27 11:00:49 +01:00
|
|
|
|
public readonly List<Wire> WiresList = new();
|
2019-09-01 22:15:34 +02:00
|
|
|
|
|
2019-09-06 10:05:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Status messages are displayed at the bottom of the UI.
|
|
|
|
|
|
/// </summary>
|
2020-09-08 13:30:22 +02:00
|
|
|
|
[ViewVariables]
|
2020-11-27 11:00:49 +01:00
|
|
|
|
private readonly Dictionary<object, object> _statuses = new();
|
2019-09-06 10:05:02 +02:00
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// <summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
/// <see cref="AssignAppearance"/> and <see cref="WiresBuilder.CreateWire"/>.
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
private readonly List<WireColor> _availableColors =
|
2020-11-27 11:00:49 +01:00
|
|
|
|
new((WireColor[]) Enum.GetValues(typeof(WireColor)));
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
|
|
|
|
|
private readonly List<WireLetter> _availableLetters =
|
2020-11-27 11:00:49 +01:00
|
|
|
|
new((WireLetter[]) Enum.GetValues(typeof(WireLetter)));
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2021-03-05 01:08:38 +01:00
|
|
|
|
[DataField("BoardName")]
|
|
|
|
|
|
private string _boardName = "Wires";
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2021-03-05 01:08:38 +01:00
|
|
|
|
[DataField("SerialNumber")]
|
2020-07-08 01:41:20 +02:00
|
|
|
|
private string? _serialNumber;
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
|
|
|
|
|
// Used to generate wire appearance randomization client side.
|
|
|
|
|
|
// We honestly don't care what it is or such but do care that it doesn't change between UI re-opens.
|
|
|
|
|
|
[ViewVariables]
|
2021-03-05 01:08:38 +01:00
|
|
|
|
[DataField("WireSeed")]
|
2022-01-26 15:26:53 +11:00
|
|
|
|
public int WireSeed;
|
2020-05-27 15:09:22 +02:00
|
|
|
|
[ViewVariables]
|
2021-03-05 01:08:38 +01:00
|
|
|
|
[DataField("LayoutId")]
|
2022-01-26 15:26:53 +11:00
|
|
|
|
public string? LayoutId = default;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
[DataField("pulseSound")] public SoundSpecifier PulseSound = new SoundPathSpecifier("/Audio/Effects/multitool_pulse.ogg");
|
2021-07-10 17:35:33 +02:00
|
|
|
|
|
|
|
|
|
|
[DataField("screwdriverOpenSound")]
|
|
|
|
|
|
private SoundSpecifier _screwdriverOpenSound = new SoundPathSpecifier("/Audio/Machines/screwdriveropen.ogg");
|
|
|
|
|
|
|
|
|
|
|
|
[DataField("screwdriverCloseSound")]
|
|
|
|
|
|
private SoundSpecifier _screwdriverCloseSound = new SoundPathSpecifier("/Audio/Machines/screwdriverclose.ogg");
|
|
|
|
|
|
|
2020-08-24 20:47:17 +02:00
|
|
|
|
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(WiresUiKey.Key);
|
2020-08-22 22:29:20 +02:00
|
|
|
|
|
2021-06-19 19:41:26 -07:00
|
|
|
|
protected override void Initialize()
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
base.Initialize();
|
2020-08-24 13:39:00 +02:00
|
|
|
|
|
2021-12-05 18:09:01 +01:00
|
|
|
|
if (_entities.TryGetComponent(Owner, out AppearanceComponent? appearance))
|
2020-08-24 13:39:00 +02:00
|
|
|
|
{
|
|
|
|
|
|
appearance.SetData(WiresVisuals.MaintenancePanelState, IsPanelOpen);
|
|
|
|
|
|
}
|
2020-08-22 22:29:20 +02:00
|
|
|
|
|
|
|
|
|
|
if (UserInterface != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
|
|
|
|
|
}
|
2020-02-27 00:16:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-06 10:05:02 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Returns whether the wire associated with <see cref="identifier"/> is cut.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
|
|
public bool IsWireCut(object identifier)
|
|
|
|
|
|
{
|
|
|
|
|
|
var wire = WiresList.Find(x => x.Identifier.Equals(identifier));
|
2020-05-27 15:09:22 +02:00
|
|
|
|
if (wire == null) throw new ArgumentException();
|
2019-09-06 10:05:02 +02:00
|
|
|
|
return wire.IsCut;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-16 00:23:23 -07:00
|
|
|
|
public sealed class Wire
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
/// The component that registered the wire.
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
public IWires Owner { get; }
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// <summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
/// Whether the wire is cut.
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
public bool IsCut { get; set; }
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// <summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
/// Used in client-server communication to identify a wire without telling the client what the wire does.
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
[ViewVariables]
|
|
|
|
|
|
public int Id { get; set; }
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// <summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
/// The color of the wire.
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
[ViewVariables]
|
|
|
|
|
|
public WireColor Color { get; }
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// <summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
/// The greek letter shown below the wire.
|
2019-09-01 22:15:34 +02:00
|
|
|
|
/// </summary>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
[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)
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
Owner = owner;
|
|
|
|
|
|
IsCut = isCut;
|
2020-05-27 15:09:22 +02:00
|
|
|
|
Color = color;
|
|
|
|
|
|
Letter = letter;
|
|
|
|
|
|
Identifier = identifier;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Used by <see cref="IWires.RegisterWires"/>.
|
|
|
|
|
|
/// </summary>
|
2022-02-16 00:23:23 -07:00
|
|
|
|
public sealed class WiresBuilder
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2021-12-05 18:09:01 +01:00
|
|
|
|
private readonly WiresComponent _wires;
|
|
|
|
|
|
private readonly IWires _owner;
|
2020-07-08 01:41:20 +02:00
|
|
|
|
private readonly WireLayout? _layout;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
|
2020-07-08 01:41:20 +02:00
|
|
|
|
public WiresBuilder(WiresComponent wires, IWires owner, WireLayout? layout)
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
_wires = wires;
|
|
|
|
|
|
_owner = owner;
|
2020-05-27 15:09:22 +02:00
|
|
|
|
_layout = layout;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-27 15:09:22 +02:00
|
|
|
|
public void CreateWire(object identifier, (WireColor, WireLetter)? appearance = null, bool isCut = false)
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2020-05-27 15:09:22 +02:00
|
|
|
|
WireLetter letter;
|
|
|
|
|
|
WireColor color;
|
|
|
|
|
|
if (!appearance.HasValue)
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2020-05-27 15:09:22 +02:00
|
|
|
|
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
|
|
|
|
|
|
{
|
|
|
|
|
|
(color, letter) = _wires.AssignAppearance();
|
|
|
|
|
|
}
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-05-27 15:09:22 +02:00
|
|
|
|
(color, letter) = appearance.Value;
|
|
|
|
|
|
_wires._availableColors.Remove(color);
|
|
|
|
|
|
_wires._availableLetters.Remove(letter);
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
|
|
|
|
|
// TODO: ENSURE NO RANDOM OVERLAP.
|
|
|
|
|
|
_wires.WiresList.Add(new Wire(_owner, isCut, color, letter, identifier));
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Picks a color from <see cref="_availableColors"/> and removes it from the list.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>The picked color.</returns>
|
2020-05-27 15:09:22 +02:00
|
|
|
|
private (WireColor, WireLetter) AssignAppearance()
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2020-05-27 15:09:22 +02:00
|
|
|
|
var color = _availableColors.Count == 0 ? WireColor.Red : _random.PickAndTake(_availableColors);
|
|
|
|
|
|
var letter = _availableLetters.Count == 0 ? WireLetter.α : _random.PickAndTake(_availableLetters);
|
|
|
|
|
|
|
|
|
|
|
|
return (color, letter);
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Call this from other components to open the wires UI.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void OpenInterface(IPlayerSession session)
|
|
|
|
|
|
{
|
2020-08-22 22:29:20 +02:00
|
|
|
|
UserInterface?.Open(session);
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-10-28 19:19:47 +01:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Closes all wire UIs.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void CloseAll()
|
|
|
|
|
|
{
|
|
|
|
|
|
UserInterface?.CloseAll();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-02-17 15:40:03 +13:00
|
|
|
|
if (!EntitySystem.Get<SharedInteractionSystem>().InRangeUnobstructed(user, Owner))
|
2022-01-26 15:26:53 +11:00
|
|
|
|
{
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg)
|
|
|
|
|
|
{
|
|
|
|
|
|
var message = serverMsg.Message;
|
|
|
|
|
|
switch (message)
|
|
|
|
|
|
{
|
|
|
|
|
|
case WiresActionMessage msg:
|
2020-05-27 15:09:22 +02:00
|
|
|
|
var wire = WiresList.Find(x => x.Id == msg.Id);
|
2022-01-26 15:26:53 +11:00
|
|
|
|
if (wire == null ||
|
|
|
|
|
|
serverMsg.Session.AttachedEntity is not {} player ||
|
|
|
|
|
|
PendingDoAfters.Contains(wire.Id))
|
2020-05-27 15:09:22 +02:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
if (!CanWiresInteract(player, out var tool))
|
2019-09-01 22:15:34 +02:00
|
|
|
|
return;
|
2020-05-08 14:01:33 +02:00
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
var doAfterSystem = EntitySystem.Get<DoAfterSystem>();
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
switch (msg.Action)
|
|
|
|
|
|
{
|
|
|
|
|
|
case WiresAction.Cut:
|
2022-01-26 15:26:53 +11:00
|
|
|
|
if (!tool.Qualities.Contains(CuttingQuality))
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2021-06-21 02:13:54 +02:00
|
|
|
|
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
2019-09-01 22:15:34 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
doAfterSystem.DoAfter(
|
|
|
|
|
|
new DoAfterEventArgs(player, CuttingTime, target: Owner)
|
|
|
|
|
|
{
|
|
|
|
|
|
TargetFinishedEvent = new WiresCutEvent
|
|
|
|
|
|
{
|
|
|
|
|
|
Wire = wire,
|
|
|
|
|
|
Tool = tool,
|
|
|
|
|
|
User = player,
|
|
|
|
|
|
},
|
|
|
|
|
|
TargetCancelledEvent = new WiresCancelledEvent()
|
|
|
|
|
|
{
|
|
|
|
|
|
Wire = wire,
|
|
|
|
|
|
},
|
|
|
|
|
|
NeedHand = true,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
PendingDoAfters.Add(wire.Id);
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
break;
|
|
|
|
|
|
case WiresAction.Mend:
|
2022-01-26 15:26:53 +11:00
|
|
|
|
if (!tool.Qualities.Contains(CuttingQuality))
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2021-06-21 02:13:54 +02:00
|
|
|
|
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
2019-09-01 22:15:34 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
doAfterSystem.DoAfter(
|
|
|
|
|
|
new DoAfterEventArgs(player, MendTime, target: Owner)
|
|
|
|
|
|
{
|
|
|
|
|
|
TargetFinishedEvent = new WiresMendedEvent()
|
|
|
|
|
|
{
|
|
|
|
|
|
Wire = wire,
|
|
|
|
|
|
Tool = tool,
|
|
|
|
|
|
User = player,
|
|
|
|
|
|
},
|
|
|
|
|
|
TargetCancelledEvent = new WiresCancelledEvent()
|
|
|
|
|
|
{
|
|
|
|
|
|
Wire = wire,
|
|
|
|
|
|
},
|
|
|
|
|
|
NeedHand = true,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
PendingDoAfters.Add(wire.Id);
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
break;
|
|
|
|
|
|
case WiresAction.Pulse:
|
2022-01-26 15:26:53 +11:00
|
|
|
|
if (!tool.Qualities.Contains(PulsingQuality))
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2021-06-21 02:13:54 +02:00
|
|
|
|
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-need-wirecutters"));
|
2019-09-01 22:15:34 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
if (wire.IsCut)
|
|
|
|
|
|
{
|
2021-06-21 02:13:54 +02:00
|
|
|
|
player.PopupMessageCursor(Loc.GetString("wires-component-ui-on-receive-message-cannot-pulse-cut-wire"));
|
2019-09-01 22:15:34 +02:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
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);
|
|
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2019-09-01 22:15:34 +02:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-01-26 15:26:53 +11:00
|
|
|
|
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()
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
|
|
|
|
|
var clientList = new List<ClientWire>();
|
|
|
|
|
|
foreach (var entry in WiresList)
|
|
|
|
|
|
{
|
2020-05-27 15:09:22 +02:00
|
|
|
|
clientList.Add(new ClientWire(entry.Id, entry.IsCut, entry.Color,
|
|
|
|
|
|
entry.Letter));
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
2020-08-22 22:29:20 +02:00
|
|
|
|
UserInterface?.SetState(
|
2020-05-27 15:09:22 +02:00
|
|
|
|
new WiresBoundUserInterfaceState(
|
|
|
|
|
|
clientList.ToArray(),
|
|
|
|
|
|
_statuses.Select(p => new StatusEntry(p.Key, p.Value)).ToArray(),
|
|
|
|
|
|
BoardName,
|
|
|
|
|
|
SerialNumber,
|
2022-01-26 15:26:53 +11:00
|
|
|
|
WireSeed));
|
2020-05-27 15:09:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-18 14:39:08 +02:00
|
|
|
|
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
2019-09-01 22:15:34 +02:00
|
|
|
|
{
|
2021-12-05 18:09:01 +01:00
|
|
|
|
if (!_entities.TryGetComponent<ToolComponent?>(eventArgs.Using, out var tool))
|
2021-02-14 06:38:41 -08:00
|
|
|
|
{
|
2020-04-29 13:43:07 +02:00
|
|
|
|
return false;
|
2021-02-14 06:38:41 -08:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-10-07 13:01:27 +02:00
|
|
|
|
var toolSystem = EntitySystem.Get<ToolSystem>();
|
|
|
|
|
|
|
2021-02-14 06:38:41 -08:00
|
|
|
|
// opens the wires ui if using a tool with cutting or multitool quality on it
|
|
|
|
|
|
if (IsPanelOpen &&
|
2022-01-26 15:26:53 +11:00
|
|
|
|
(tool.Qualities.Contains(CuttingQuality) ||
|
|
|
|
|
|
tool.Qualities.Contains(PulsingQuality)))
|
2021-02-14 06:38:41 -08:00
|
|
|
|
{
|
2021-12-05 18:09:01 +01:00
|
|
|
|
if (_entities.TryGetComponent(eventArgs.User, out ActorComponent? actor))
|
2021-02-14 06:38:41 -08:00
|
|
|
|
{
|
2021-05-12 13:42:18 +02:00
|
|
|
|
OpenInterface(actor.PlayerSession);
|
2021-02-14 06:38:41 -08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// screws the panel open if the tool can do so
|
2021-12-03 15:53:09 +01:00
|
|
|
|
else if (await toolSystem.UseTool(tool.Owner, eventArgs.User, Owner,
|
2022-01-26 15:26:53 +11:00
|
|
|
|
0f, WireHackingSystem.ScrewTime, ScrewingQuality, toolComponent:tool))
|
2021-02-14 06:38:41 -08:00
|
|
|
|
{
|
|
|
|
|
|
IsPanelOpen = !IsPanelOpen;
|
2021-07-10 17:35:33 +02:00
|
|
|
|
if (IsPanelOpen)
|
|
|
|
|
|
{
|
2021-07-31 19:52:33 +02:00
|
|
|
|
SoundSystem.Play(Filter.Pvs(Owner), _screwdriverOpenSound.GetSound(), Owner);
|
2021-07-10 17:35:33 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2021-07-31 19:52:33 +02:00
|
|
|
|
SoundSystem.Play(Filter.Pvs(Owner), _screwdriverCloseSound.GetSound(), Owner);
|
2021-07-10 17:35:33 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-02-14 06:38:41 -08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2019-10-13 19:45:25 +02:00
|
|
|
|
|
2021-02-14 06:38:41 -08:00
|
|
|
|
return false;
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-27 15:09:22 +02:00
|
|
|
|
public void SetStatus(object statusIdentifier, object status)
|
2019-09-06 10:05:02 +02:00
|
|
|
|
{
|
|
|
|
|
|
if (_statuses.TryGetValue(statusIdentifier, out var storedMessage))
|
|
|
|
|
|
{
|
2020-05-27 15:09:22 +02:00
|
|
|
|
if (storedMessage == status)
|
2019-09-06 10:05:02 +02:00
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-05-27 15:09:22 +02:00
|
|
|
|
|
|
|
|
|
|
_statuses[statusIdentifier] = status;
|
2019-09-06 10:05:02 +02:00
|
|
|
|
UpdateUserInterface();
|
|
|
|
|
|
}
|
2019-09-01 22:15:34 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|